From caf34a717f8d2694bc483e8d29e37e62966c9dda Mon Sep 17 00:00:00 2001 From: Juliet Levesque Date: Tue, 13 Feb 2024 15:48:59 -0800 Subject: [PATCH] [Nearby Presence] Read response data from remote device see go/cros-nearby-presence-np-nc-authentication for details. PiperOrigin-RevId: 606772097 --- presence/BUILD | 2 + presence/implementation/BUILD | 12 ++- .../implementation/connection_authenticator.h | 22 +++-- ...or.cc => connection_authenticator_impl.cc} | 10 +-- .../connection_authenticator_impl.h | 85 +++++++++++++++++++ ... => connection_authenticator_impl_test.cc} | 58 ++++++------- .../mock_connection_authenticator.h | 63 ++++++++++++++ presence/presence_device_provider.cc | 82 +++++++++++++++--- presence/presence_device_provider.h | 12 ++- presence/presence_device_provider_test.cc | 74 ++++++++++++++-- presence/presence_service_impl.cc | 30 +++---- presence/presence_service_impl.h | 22 +++-- 12 files changed, 378 insertions(+), 94 deletions(-) rename presence/implementation/{connection_authenticator.cc => connection_authenticator_impl.cc} (96%) create mode 100644 presence/implementation/connection_authenticator_impl.h rename presence/implementation/{connection_authenticator_test.cc => connection_authenticator_impl_test.cc} (87%) create mode 100644 presence/implementation/mock_connection_authenticator.h diff --git a/presence/BUILD b/presence/BUILD index ef41993f..5c1d61a0 100644 --- a/presence/BUILD +++ b/presence/BUILD @@ -35,6 +35,7 @@ cc_library( "//internal/interop:device", "//internal/platform:base", "//internal/platform:types", + "//internal/platform/implementation:comm", "//internal/platform/implementation:types", "//internal/proto:local_credential_cc_proto", "//internal/proto:metadata_cc_proto", @@ -195,6 +196,7 @@ cc_test( "//internal/proto:credential_cc_proto", "//internal/proto:local_credential_cc_proto", "//internal/proto:metadata_cc_proto", + "//presence/implementation:internal", "//presence/implementation:internal_test", "//presence/proto:presence_frame_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", diff --git a/presence/implementation/BUILD b/presence/implementation/BUILD index 52b96d63..e9231ea4 100644 --- a/presence/implementation/BUILD +++ b/presence/implementation/BUILD @@ -56,7 +56,7 @@ cc_library( "advertisement_factory.cc", "base_broadcast_request.cc", "broadcast_manager.cc", - "connection_authenticator.cc", + "connection_authenticator_impl.cc", "credential_manager_impl.cc", "ldt.cc", "scan_manager.cc", @@ -69,6 +69,7 @@ cc_library( "base_broadcast_request.h", "broadcast_manager.h", "connection_authenticator.h", + "connection_authenticator_impl.h", "credential_manager.h", "credential_manager_impl.h", "ldt.h", @@ -137,6 +138,7 @@ cc_library( srcs = [ ], hdrs = [ + "mock_connection_authenticator.h", "mock_credential_manager.h", "mock_service_controller.h", ], @@ -146,7 +148,11 @@ cc_library( deps = [ ":internal", "//internal/platform/implementation:comm", + "//internal/proto:credential_cc_proto", + "//internal/proto:local_credential_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings:string_view", "@com_google_googletest//:gtest_main", ], @@ -283,9 +289,9 @@ cc_test( ) cc_test( - name = "connection_authenticator_test", + name = "connection_authenticator_impl_test", size = "small", - srcs = ["connection_authenticator_test.cc"], + srcs = ["connection_authenticator_impl_test.cc"], deps = [ ":internal", "//internal/crypto", diff --git a/presence/implementation/connection_authenticator.h b/presence/implementation/connection_authenticator.h index 0933a966..7a9b2cb8 100644 --- a/presence/implementation/connection_authenticator.h +++ b/presence/implementation/connection_authenticator.h @@ -45,6 +45,8 @@ class ConnectionAuthenticator { using InitiatorData = absl::variant; + virtual ~ConnectionAuthenticator() = default; + // Builds a signed message to be returned to Nearby Connections for // authentication on the other side of the connection. // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. @@ -53,10 +55,10 @@ class ConnectionAuthenticator { // performing one-way authentication. // shared_credential - The shared credential used to decrypt the advertisement // from the remote device. - absl::StatusOr BuildSignedMessageAsInitiator( + virtual absl::StatusOr BuildSignedMessageAsInitiator( absl::string_view ukey2_secret, std::optional local_credential, - const internal::SharedCredential& shared_credential) const; + const internal::SharedCredential& shared_credential) const = 0; // Builds a signed message to be returned to Nearby Connections for // authentication on the other side of the connection. @@ -64,9 +66,9 @@ class ConnectionAuthenticator { // local_credential - The local credential used to sign the derived // information so the initiator can verify against our // shared credential. - absl::StatusOr BuildSignedMessageAsResponder( + virtual absl::StatusOr BuildSignedMessageAsResponder( absl::string_view ukey2_secret, - const internal::LocalCredential& local_credential) const; + const internal::LocalCredential& local_credential) const = 0; // Verifies a signed message received from the responder (broadcaster) of the // Nearby Presence advertisement. @@ -75,22 +77,24 @@ class ConnectionAuthenticator { // ukey2_secret - the shared secret derived from the ukey2 handshake in NC. // shared_credentials - the set of shared credentials that can be used to // verify the responder data. - absl::Status VerifyMessageAsInitiator( + virtual absl::Status VerifyMessageAsInitiator( ResponderData authentication_data, absl::string_view ukey2_secret, - const std::vector& shared_credentials) const; + const std::vector& shared_credentials) + const = 0; // Verifies a signed message received from the Nearby Connections peer. - // Returns absl::OkStatus() if the verification was successful. + // Returns the matched local credential if the verification was successful. // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. // received_frame - The received frame from Nearby Connections. // local_credentials - The set of local credentials that may contain the // required keyseed hash. // shared_credentials - The set of shared credentials that can be used to // verify the signed contents of the frame. - absl::StatusOr VerifyMessageAsResponder( + virtual absl::StatusOr VerifyMessageAsResponder( absl::string_view ukey2_secret, InitiatorData initiator_data, const std::vector& local_credentials, - const std::vector& shared_credentials) const; + const std::vector& shared_credentials) + const = 0; }; } // namespace presence diff --git a/presence/implementation/connection_authenticator.cc b/presence/implementation/connection_authenticator_impl.cc similarity index 96% rename from presence/implementation/connection_authenticator.cc rename to presence/implementation/connection_authenticator_impl.cc index 4ee90609..cbe68aa2 100644 --- a/presence/implementation/connection_authenticator.cc +++ b/presence/implementation/connection_authenticator_impl.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "presence/implementation/connection_authenticator.h" +#include "presence/implementation/connection_authenticator_impl.h" #include #include @@ -47,7 +47,7 @@ constexpr char kDiscovererHkdfInfo[] = } // namespace absl::StatusOr -ConnectionAuthenticator::BuildSignedMessageAsInitiator( +ConnectionAuthenticatorImpl::BuildSignedMessageAsInitiator( absl::string_view ukey2_secret, std::optional local_credential, const internal::SharedCredential& shared_credential) const { @@ -78,7 +78,7 @@ ConnectionAuthenticator::BuildSignedMessageAsInitiator( } absl::StatusOr -ConnectionAuthenticator::BuildSignedMessageAsResponder( +ConnectionAuthenticatorImpl::BuildSignedMessageAsResponder( absl::string_view ukey2_secret, const internal::LocalCredential& local_credential) const { auto signer = crypto::Ed25519Signer::Create( @@ -95,7 +95,7 @@ ConnectionAuthenticator::BuildSignedMessageAsResponder( *pkey_signature}; } -absl::Status ConnectionAuthenticator::VerifyMessageAsInitiator( +absl::Status ConnectionAuthenticatorImpl::VerifyMessageAsInitiator( ResponderData authentication_data, absl::string_view ukey2_secret, const std::vector& shared_credentials) const { if (authentication_data.private_key_signature.empty()) { @@ -119,7 +119,7 @@ absl::Status ConnectionAuthenticator::VerifyMessageAsInitiator( } absl::StatusOr -ConnectionAuthenticator::VerifyMessageAsResponder( +ConnectionAuthenticatorImpl::VerifyMessageAsResponder( absl::string_view ukey2_secret, InitiatorData initiator_data, const std::vector& local_credentials, const std::vector& shared_credentials) const { diff --git a/presence/implementation/connection_authenticator_impl.h b/presence/implementation/connection_authenticator_impl.h new file mode 100644 index 00000000..25f42ddc --- /dev/null +++ b/presence/implementation/connection_authenticator_impl.h @@ -0,0 +1,85 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_IMPL_H_ +#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_IMPL_H_ + +#include +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "internal/proto/credential.pb.h" +#include "internal/proto/local_credential.pb.h" +#include "presence/implementation/connection_authenticator.h" + +namespace nearby { +namespace presence { + +class ConnectionAuthenticatorImpl : public ConnectionAuthenticator { + public: + // Builds a signed message to be returned to Nearby Connections for + // authentication on the other side of the connection. + // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. + // local_credential - The local credential used to sign the derived + // information. If this is std::nullopt, then we will be + // performing one-way authentication. + // shared_credential - The shared credential used to decrypt the advertisement + // from the remote device. + absl::StatusOr BuildSignedMessageAsInitiator( + absl::string_view ukey2_secret, + std::optional local_credential, + const internal::SharedCredential& shared_credential) const override; + + // Builds a signed message to be returned to Nearby Connections for + // authentication on the other side of the connection. + // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. + // local_credential - The local credential used to sign the derived + // information so the initiator can verify against our + // shared credential. + absl::StatusOr BuildSignedMessageAsResponder( + absl::string_view ukey2_secret, + const internal::LocalCredential& local_credential) const override; + + // Verifies a signed message received from the responder (broadcaster) of the + // Nearby Presence advertisement. + // authentication_data - the data required to verify the connection, received + // from the responder. + // ukey2_secret - the shared secret derived from the ukey2 handshake in NC. + // shared_credentials - the set of shared credentials that can be used to + // verify the responder data. + absl::Status VerifyMessageAsInitiator( + ResponderData authentication_data, absl::string_view ukey2_secret, + const std::vector& shared_credentials) + const override; + + // Verifies a signed message received from the Nearby Connections peer. + // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. + // received_frame - The received frame from Nearby Connections. + // local_credentials - The set of local credentials that may contain the + // required keyseed hash. + // shared_credentials - The set of shared credentials that can be used to + // verify the signed contents of the frame. + absl::StatusOr VerifyMessageAsResponder( + absl::string_view ukey2_secret, InitiatorData initiator_data, + const std::vector& local_credentials, + const std::vector& shared_credentials) + const override; +}; + +} // namespace presence +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_IMPL_H_ diff --git a/presence/implementation/connection_authenticator_test.cc b/presence/implementation/connection_authenticator_impl_test.cc similarity index 87% rename from presence/implementation/connection_authenticator_test.cc rename to presence/implementation/connection_authenticator_impl_test.cc index 5e2e042e..e28eb477 100644 --- a/presence/implementation/connection_authenticator_test.cc +++ b/presence/implementation/connection_authenticator_impl_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "presence/implementation/connection_authenticator.h" +#include "presence/implementation/connection_authenticator_impl.h" #include #include @@ -79,8 +79,8 @@ class PresenceAuthenticatorTest : public ::testing::Test { }; TEST_F(PresenceAuthenticatorTest, TestTwoWayInitiatorSignResponderVerify) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, initiator_authenticator.BuildSignedMessageAsInitiator( kUkey2Secret, initiator_local_credential_, @@ -93,8 +93,8 @@ TEST_F(PresenceAuthenticatorTest, TestTwoWayInitiatorSignResponderVerify) { } TEST_F(PresenceAuthenticatorTest, TestOneWayInitiatorSignResponderVerify) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN( ConnectionAuthenticator::InitiatorData auth_data, initiator_authenticator.BuildSignedMessageAsInitiator( @@ -107,8 +107,8 @@ TEST_F(PresenceAuthenticatorTest, TestOneWayInitiatorSignResponderVerify) { } TEST_F(PresenceAuthenticatorTest, TestResponderSignInitiatorVerify) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data, responder_authenticator.BuildSignedMessageAsResponder( kUkey2Secret, responder_local_credential_)); @@ -118,8 +118,8 @@ TEST_F(PresenceAuthenticatorTest, TestResponderSignInitiatorVerify) { TEST_F(PresenceAuthenticatorTest, TestTwoWayInitiatorSignResponderVerifyNoSharedCredentialMatchFails) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, initiator_authenticator.BuildSignedMessageAsInitiator( kUkey2Secret, initiator_local_credential_, @@ -131,8 +131,8 @@ TEST_F(PresenceAuthenticatorTest, TEST_F(PresenceAuthenticatorTest, TestOneWayInitiatorSignResponderVerifyNoMatchCredentialFails) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN( ConnectionAuthenticator::InitiatorData auth_data, initiator_authenticator.BuildSignedMessageAsInitiator( @@ -144,8 +144,8 @@ TEST_F(PresenceAuthenticatorTest, TEST_F(PresenceAuthenticatorTest, TestOneWayInitiatorSignResponderVerifyNoCredentialFails) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN( ConnectionAuthenticator::InitiatorData auth_data, initiator_authenticator.BuildSignedMessageAsInitiator( @@ -157,8 +157,8 @@ TEST_F(PresenceAuthenticatorTest, TEST_F(PresenceAuthenticatorTest, TestTwoWayInitiatorSignResponderVerifyNoMatchCredentialFails) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, initiator_authenticator.BuildSignedMessageAsInitiator( kUkey2Secret, initiator_local_credential_, @@ -170,8 +170,8 @@ TEST_F(PresenceAuthenticatorTest, TEST_F(PresenceAuthenticatorTest, TestTwoWayInitiatorSignResponderVerifyWrongKeyFails) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, initiator_authenticator.BuildSignedMessageAsInitiator( kUkey2Secret, initiator_local_credential_, @@ -184,8 +184,8 @@ TEST_F(PresenceAuthenticatorTest, TEST_F(PresenceAuthenticatorTest, TestResponderSignInitiatorVerifyNoMatchCredentialFails) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data, responder_authenticator.BuildSignedMessageAsResponder( kUkey2Secret, responder_local_credential_)); @@ -196,8 +196,8 @@ TEST_F(PresenceAuthenticatorTest, TEST_F(PresenceAuthenticatorTest, TestResponderSignInitiatorVerifyWrongKeyFails) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data, responder_authenticator.BuildSignedMessageAsResponder( kUkey2Secret, responder_local_credential_)); @@ -209,8 +209,8 @@ TEST_F(PresenceAuthenticatorTest, TEST_F(PresenceAuthenticatorTest, TestTwoWayInitiatorSignResponderVerifyNoCidHashFails) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, initiator_authenticator.BuildSignedMessageAsInitiator( kUkey2Secret, initiator_local_credential_, @@ -225,8 +225,8 @@ TEST_F(PresenceAuthenticatorTest, TEST_F(PresenceAuthenticatorTest, TestTwoWayInitiatorSignResponderVerifyNoPkeySigFails) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, initiator_authenticator.BuildSignedMessageAsInitiator( kUkey2Secret, initiator_local_credential_, @@ -241,8 +241,8 @@ TEST_F(PresenceAuthenticatorTest, TEST_F(PresenceAuthenticatorTest, TestOneWayInitiatorSignResponderVerifyNoCidHashFails) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN( ConnectionAuthenticator::InitiatorData auth_data, initiator_authenticator.BuildSignedMessageAsInitiator( @@ -257,8 +257,8 @@ TEST_F(PresenceAuthenticatorTest, TEST_F(PresenceAuthenticatorTest, TestResponderSignInitiatorVerifyNoPkeySigFail) { - ConnectionAuthenticator responder_authenticator; - ConnectionAuthenticator initiator_authenticator; + ConnectionAuthenticatorImpl responder_authenticator; + ConnectionAuthenticatorImpl initiator_authenticator; ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data, responder_authenticator.BuildSignedMessageAsResponder( kUkey2Secret, responder_local_credential_)); diff --git a/presence/implementation/mock_connection_authenticator.h b/presence/implementation/mock_connection_authenticator.h new file mode 100644 index 00000000..5b646c80 --- /dev/null +++ b/presence/implementation/mock_connection_authenticator.h @@ -0,0 +1,63 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MOCK_CONNECTION_AUTHENTICATOR_H_ +#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MOCK_CONNECTION_AUTHENTICATOR_H_ + +#include +#include + +#include "gmock/gmock.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "internal/proto/credential.pb.h" +#include "internal/proto/local_credential.pb.h" +#include "presence/implementation/connection_authenticator.h" + +namespace nearby { +namespace presence { + +/* + * This class is for unit tests, mocking {@code ConnectionAuthenticator} + * functions in `PresenceDeviceProviderTest`. + */ +class MockConnectionAuthenticator : public ConnectionAuthenticator { + public: + MOCK_METHOD(absl::StatusOr, BuildSignedMessageAsInitiator, + (absl::string_view ukey2_secret, + std::optional local_credential, + const internal::SharedCredential& shared_credential), + (const override)); + MOCK_METHOD(absl::StatusOr, BuildSignedMessageAsResponder, + (absl::string_view ukey2_secret, + const internal::LocalCredential& local_credential), + (const override)); + MOCK_METHOD( + absl::Status, VerifyMessageAsInitiator, + (ResponderData authentication_data, absl::string_view ukey2_secret, + const std::vector& shared_credentials), + (const override)); + MOCK_METHOD( + absl::StatusOr, VerifyMessageAsResponder, + (absl::string_view ukey2_secret, InitiatorData initiator_data, + const std::vector& local_credentials, + const std::vector& shared_credentials), + (const override)); +}; + +} // namespace presence +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MOCK_CONNECTION_AUTHENTICATOR_H_ diff --git a/presence/presence_device_provider.cc b/presence/presence_device_provider.cc index 8316c242..3b4628e1 100644 --- a/presence/presence_device_provider.cc +++ b/presence/presence_device_provider.cc @@ -18,6 +18,7 @@ #include #include +#include "absl/log/check.h" #include "absl/types/variant.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" @@ -96,9 +97,13 @@ PresenceAuthenticationFrame BuildInitiatorPresenceAuthenticationFrame( } // namespace PresenceDeviceProvider::PresenceDeviceProvider( - ServiceController* service_controller) + ServiceController* service_controller, + const ConnectionAuthenticator* connection_authenticator) : service_controller_(*service_controller), - device_{service_controller_.GetLocalDeviceMetadata()} {} + device_{service_controller_.GetLocalDeviceMetadata()}, + connection_authenticator_(*connection_authenticator) { + CHECK(connection_authenticator); +} AuthenticationStatus PresenceDeviceProvider::AuthenticateAsInitiator( const NearbyDevice& remote_device, absl::string_view shared_secret, @@ -110,9 +115,12 @@ AuthenticationStatus PresenceDeviceProvider::AuthenticateAsInitiator( // iterates over the returned list and returns the local credential // that corresponds with the current time. // - // TODO(b/304843571): Add support for additional IdentityTypes. Currently, - // only `IDENTITY_TYPE_PRIVATE` is supported in order to unblock Nearby - // Presence MVP. + // TODO(b/304843571): Add support for additional IdentityTypes and for + // AuthenticationStatus::kUnknown. Currently, only `IDENTITY_TYPE_PRIVATE` is + // supported in order to unblock Nearby Presence MVP on CrOS, however in + // order to support future IdentityTypes, there needs to be a way to + // plumb in the requested identity type, as well as report back the + // unknown result to callers in NC. service_controller_.GetLocalCredentials( /*credential_selector=*/{.manager_app_id = manager_app_id_, .account_name = @@ -141,7 +149,7 @@ AuthenticationStatus PresenceDeviceProvider::AuthenticateAsInitiator( // 2. Construct the frame and write to the // |authentication_transport|. if (!WriteToRemoteDevice( - /*remote_device=*/&remote_device, + /*remote_device=*/remote_device, /*shared_secret=*/shared_secret, /*authentication_transport=*/authentication_transport, /*local_credential=*/credential.value(), @@ -150,12 +158,17 @@ AuthenticationStatus PresenceDeviceProvider::AuthenticateAsInitiator( return; } - // TODO(b/282027237): Continue with the following steps, which will - // be done in follow up CL's. // 3. Read the message from the remote device via - // |authentication_transport|. + // |authentication_transport| and verify the response data. + if (!ReadAndVerifyRemoteDeviceData( + /*remote_device=*/remote_device, + /*shared_secret=*/shared_secret, + /*authentication_transport=*/authentication_transport)) { + response.Set(AuthenticationStatus::kFailure); + return; + } + // 4. Return the status of the authentication to the callers. - // For now, return success on the Future. response.Set(AuthenticationStatus::kSuccess); }}); @@ -169,7 +182,7 @@ AuthenticationStatus PresenceDeviceProvider::AuthenticateAsInitiator( } bool PresenceDeviceProvider::WriteToRemoteDevice( - const NearbyDevice* remote_device, absl::string_view shared_secret, + const NearbyDevice& remote_device, absl::string_view shared_secret, const AuthenticationTransport& authentication_transport, const internal::LocalCredential& local_credential, Future& response) const { @@ -177,7 +190,7 @@ bool PresenceDeviceProvider::WriteToRemoteDevice( // it's shared credentials, which is safe to do since the |remote_device| // passed to the `PresenceDeviceProvider` will always be a `PresenceDevice`. const PresenceDevice* remote_presence_device = - static_cast(remote_device); + static_cast(&remote_device); auto shared_credential = remote_presence_device->GetDecryptSharedCredential(); if (!shared_credential.has_value()) { NEARBY_LOGS(INFO) @@ -190,8 +203,6 @@ bool PresenceDeviceProvider::WriteToRemoteDevice( connection_authenticator_.BuildSignedMessageAsInitiator( /*ukey2_secret=*/shared_secret, /*local_credential=*/local_credential, /*shared_credential=*/shared_credential.value()); - // TODO(b/317219088): Add test covereage for when - // `ConnectionAuthenticator::BuildSignedMessageAsInitiator()` fails. if (!status_or_initiator_data.ok()) { NEARBY_LOGS(INFO) << __func__ << ": failure to build signed message as initiator"; @@ -207,5 +218,48 @@ bool PresenceDeviceProvider::WriteToRemoteDevice( return true; } +bool PresenceDeviceProvider::ReadAndVerifyRemoteDeviceData( + const NearbyDevice& remote_device, absl::string_view shared_secret, + const AuthenticationTransport& authentication_transport) const { + // Fetch the local public credentials to be used to verify the response data. + Future read_and_verify_result; + service_controller_.GetLocalPublicCredentials( + /*credential_selector=*/{.manager_app_id = manager_app_id_, + .account_name = + device_.GetMetadata().account_name(), + .identity_type = ::nearby::internal:: + IdentityType::IDENTITY_TYPE_PRIVATE}, + /*callback=*/{.credentials_fetched_cb = [this, &read_and_verify_result, + &authentication_transport, + &shared_secret]( + auto status_or_credentials) { + if (!status_or_credentials.ok()) { + NEARBY_LOGS(INFO) + << __func__ << ": failure to fetch local public credentials"; + read_and_verify_result.Set(/*success=*/false); + return; + } + + std::string response_data = authentication_transport.ReadMessage(); + auto status = connection_authenticator_.VerifyMessageAsInitiator( + /*authentication_data=*/{.private_key_signature = response_data}, + /*ukey2_secret=*/shared_secret, + /*shared_credential=*/status_or_credentials.value()); + if (!status.ok()) { + NEARBY_LOGS(INFO) << __func__ << ": failure to verify remote device"; + read_and_verify_result.Set(/*success=*/false); + return; + } + + read_and_verify_result.Set(/*success=*/true); + }}); + + NEARBY_LOGS(INFO) << __func__ << ": Waiting for future to complete"; + ExceptionOr result = read_and_verify_result.Get(); + NEARBY_LOGS(INFO) << "Future:[" << __func__ + << "] completed with status:" << result.result(); + return result.result(); +} + } // namespace presence } // namespace nearby diff --git a/presence/presence_device_provider.h b/presence/presence_device_provider.h index 7bbc911e..001f9f2f 100644 --- a/presence/presence_device_provider.h +++ b/presence/presence_device_provider.h @@ -15,6 +15,7 @@ #ifndef THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_DEVICE_PROVIDER_H_ #define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_DEVICE_PROVIDER_H_ +#include #include #include "absl/strings/string_view.h" @@ -34,7 +35,9 @@ class ServiceController; class PresenceDeviceProvider : public NearbyDeviceProvider { public: - explicit PresenceDeviceProvider(ServiceController* service_controller); + PresenceDeviceProvider( + ServiceController* service_controller, + const ConnectionAuthenticator* connection_authenticator); const NearbyDevice* GetLocalDevice() override { return &device_; } @@ -70,15 +73,18 @@ class PresenceDeviceProvider : public NearbyDeviceProvider { private: bool WriteToRemoteDevice( - const NearbyDevice* remote_device, absl::string_view shared_secret, + const NearbyDevice& remote_device, absl::string_view shared_secret, const AuthenticationTransport& authentication_transport, const internal::LocalCredential& local_credential, Future& response) const; + bool ReadAndVerifyRemoteDeviceData( + const NearbyDevice& remote_device, absl::string_view shared_secret, + const AuthenticationTransport& authentication_transport) const; ServiceController& service_controller_; PresenceDevice device_; std::string manager_app_id_; - ConnectionAuthenticator connection_authenticator_; + const ConnectionAuthenticator& connection_authenticator_; }; } // namespace presence diff --git a/presence/presence_device_provider_test.cc b/presence/presence_device_provider_test.cc index 9814dbf2..affe0ac3 100644 --- a/presence/presence_device_provider_test.cc +++ b/presence/presence_device_provider_test.cc @@ -35,6 +35,8 @@ #include "internal/proto/credential.pb.h" #include "internal/proto/local_credential.pb.h" #include "internal/proto/metadata.pb.h" +#include "presence/implementation/connection_authenticator.h" +#include "presence/implementation/mock_connection_authenticator.h" #include "presence/implementation/mock_service_controller.h" #include "presence/presence_device.h" #include "presence/proto/presence_frame.pb.h" @@ -49,6 +51,8 @@ constexpr absl::string_view kManagerAppId = "test_app_id"; constexpr char kUkey2Secret[] = {0x34, 0x56, 0x78, 0x90}; constexpr char kKeySeed[] = {1, 2, 3, 4, 5, 6, 7, 8}; constexpr int kPresenceVersion = 1; +constexpr absl::string_view kSharedCredentialHash = "shared_cred_hash"; +constexpr absl::string_view kPrivateKeySignature = "private_key_signature"; Metadata CreateTestMetadata() { Metadata metadata; @@ -90,6 +94,13 @@ internal::SharedCredential BuildSharedCredential( return shared_credential; } +ConnectionAuthenticator::TwoWayInitiatorData BuildDefaultInitiatorData() { + ConnectionAuthenticator::TwoWayInitiatorData data; + data.shared_credential_hash = kSharedCredentialHash; + data.private_key_signature = kPrivateKeySignature; + return data; +} + class MockAuthenticationTransport : public AuthenticationTransport { public: MOCK_METHOD(void, WriteMessage, (absl::string_view), (const override)); @@ -101,8 +112,8 @@ class PresenceDeviceProviderTest : public ::testing::Test { PresenceDeviceProviderTest() { ON_CALL(mock_service_controller_, GetLocalDeviceMetadata) .WillByDefault(testing::Return(CreateTestMetadata())); - provider_ = - std::make_unique(&mock_service_controller_); + provider_ = std::make_unique( + &mock_service_controller_, &mock_connection_authenticator_); } void SetUp() override { @@ -114,6 +125,7 @@ class PresenceDeviceProviderTest : public ::testing::Test { MockServiceController mock_service_controller_; std::unique_ptr provider_; crypto::Ed25519KeyPair key_pair_; + MockConnectionAuthenticator mock_connection_authenticator_; }; TEST_F(PresenceDeviceProviderTest, ProviderIsNotTriviallyConstructible) { @@ -200,7 +212,7 @@ TEST_F(PresenceDeviceProviderTest, EXPECT_EQ(AuthenticationStatus::kFailure, status); } -TEST_F(PresenceDeviceProviderTest, AuthenticateAsInitiator_Success) { +TEST_F(PresenceDeviceProviderTest, AuthenticateAsInitiator_FailureToVerify) { EXPECT_CALL(mock_service_controller_, GetLocalCredentials) .WillOnce([&](const CredentialSelector& credential_selector, GetLocalCredentialsResultCallback callback) { @@ -208,10 +220,63 @@ TEST_F(PresenceDeviceProviderTest, AuthenticateAsInitiator_Success) { credentials.push_back(CreateValidLocalCredential(key_pair_)); std::move(callback.credentials_fetched_cb)(credentials); }); + EXPECT_CALL(mock_service_controller_, GetLocalPublicCredentials) + .WillOnce([&](const CredentialSelector& credential_selector, + GetPublicCredentialsResultCallback callback) { + std::vector credentials; + credentials.push_back(BuildSharedCredential(key_pair_)); + std::move(callback.credentials_fetched_cb)(credentials); + }); PresenceDevice remote_device(CreateTestMetadata()); remote_device.SetDecryptSharedCredential(BuildSharedCredential(key_pair_)); + MockAuthenticationTransport authentication_transport; + EXPECT_CALL(authentication_transport, WriteMessage) + .WillOnce([&](absl::string_view message) { + PresenceAuthenticationFrame authentication_frame; + EXPECT_TRUE(authentication_frame.ParseFromString(message)); + EXPECT_EQ(kPresenceVersion, authentication_frame.version()); + }); + EXPECT_CALL(authentication_transport, ReadMessage).WillOnce([&]() { + PresenceAuthenticationFrame authentication_frame; + return authentication_frame.SerializeAsString(); + }); + + EXPECT_CALL(mock_connection_authenticator_, BuildSignedMessageAsInitiator) + .WillOnce(testing::Return(BuildDefaultInitiatorData())); + EXPECT_CALL(mock_connection_authenticator_, VerifyMessageAsInitiator) + .WillOnce(testing::Return( + absl::Status(absl::StatusCode::kCancelled, /*msg=*/std::string()))); + + auto status = provider_->AuthenticateAsInitiator( + /*remote_device=*/remote_device, /*shared_secret=*/kUkey2Secret, + /*authentication_transport=*/authentication_transport); + EXPECT_EQ(AuthenticationStatus::kFailure, status); +} + +TEST_F(PresenceDeviceProviderTest, AuthenticateAsInitiator_Success) { + EXPECT_CALL(mock_service_controller_, GetLocalCredentials) + .WillOnce([&](const CredentialSelector& credential_selector, + GetLocalCredentialsResultCallback callback) { + std::vector credentials; + credentials.push_back(CreateValidLocalCredential(key_pair_)); + std::move(callback.credentials_fetched_cb)(credentials); + }); + EXPECT_CALL(mock_service_controller_, GetLocalPublicCredentials) + .WillOnce([&](const CredentialSelector& credential_selector, + GetPublicCredentialsResultCallback callback) { + std::vector credentials; + credentials.push_back(BuildSharedCredential(key_pair_)); + std::move(callback.credentials_fetched_cb)(std::move(credentials)); + }); + + PresenceDevice remote_device(CreateTestMetadata()); + remote_device.SetDecryptSharedCredential(BuildSharedCredential(key_pair_)); + + ON_CALL(mock_connection_authenticator_, BuildSignedMessageAsInitiator) + .WillByDefault(testing::Return(BuildDefaultInitiatorData())); + MockAuthenticationTransport authentication_transport; EXPECT_CALL(authentication_transport, WriteMessage) .WillOnce([&](absl::string_view message) { @@ -224,9 +289,6 @@ TEST_F(PresenceDeviceProviderTest, AuthenticateAsInitiator_Success) { /*remote_device=*/remote_device, /*shared_secret=*/kUkey2Secret, /*authentication_transport=*/authentication_transport); - // TODO(b/282027237): Once additional logic is added in follow up CL's - // to continue the authentication, add coverage in this unit test for a - // success case. EXPECT_EQ(AuthenticationStatus::kSuccess, status); } diff --git a/presence/presence_service_impl.cc b/presence/presence_service_impl.cc index 660bb609..f62f35b2 100644 --- a/presence/presence_service_impl.cc +++ b/presence/presence_service_impl.cc @@ -20,41 +20,33 @@ #include "internal/platform/borrowable.h" #include "presence/data_types.h" -#include "presence/implementation/service_controller_impl.h" #include "presence/presence_client_impl.h" #include "presence/presence_device_provider.h" namespace nearby { namespace presence { -PresenceServiceImpl::PresenceServiceImpl() { - service_controller_ = std::make_unique( - &executor_, &credential_manager_, &scan_manager_, &broadcast_manager_); - provider_ = - std::make_unique(service_controller_.get()); -} - std::unique_ptr PresenceServiceImpl::CreatePresenceClient() { return PresenceClientImpl::Factory::Create(lender_.GetBorrowable()); } absl::StatusOr PresenceServiceImpl::StartScan( ScanRequest scan_request, ScanCallback callback) { - return service_controller_->StartScan(scan_request, std::move(callback)); + return service_controller_.StartScan(scan_request, std::move(callback)); } void PresenceServiceImpl::StopScan(ScanSessionId id) { - service_controller_->StopScan(id); + service_controller_.StopScan(id); } absl::StatusOr PresenceServiceImpl::StartBroadcast( BroadcastRequest broadcast_request, BroadcastCallback callback) { - return service_controller_->StartBroadcast(broadcast_request, - std::move(callback)); + return service_controller_.StartBroadcast(broadcast_request, + std::move(callback)); } void PresenceServiceImpl::StopBroadcast(BroadcastSessionId session) { - service_controller_->StopBroadcast(session); + service_controller_.StopBroadcast(session); } void PresenceServiceImpl::UpdateLocalDeviceMetadata( @@ -63,9 +55,9 @@ void PresenceServiceImpl::UpdateLocalDeviceMetadata( const std::vector& identity_types, int credential_life_cycle_days, int contiguous_copy_of_credentials, GenerateCredentialsResultCallback credentials_generated_cb) { - provider_->UpdateMetadata(metadata); - provider_->SetManagerAppId(manager_app_id); - service_controller_->UpdateLocalDeviceMetadata( + provider_.UpdateMetadata(metadata); + provider_.SetManagerAppId(manager_app_id); + service_controller_.UpdateLocalDeviceMetadata( metadata, regen_credentials, manager_app_id, identity_types, credential_life_cycle_days, contiguous_copy_of_credentials, std::move(credentials_generated_cb)); @@ -74,15 +66,15 @@ void PresenceServiceImpl::UpdateLocalDeviceMetadata( void PresenceServiceImpl::GetLocalPublicCredentials( const CredentialSelector& credential_selector, GetPublicCredentialsResultCallback callback) { - service_controller_->GetLocalPublicCredentials(credential_selector, - std::move(callback)); + service_controller_.GetLocalPublicCredentials(credential_selector, + std::move(callback)); } void PresenceServiceImpl::UpdateRemotePublicCredentials( absl::string_view manager_app_id, absl::string_view account_name, const std::vector& remote_public_creds, UpdateRemotePublicCredentialsCallback credentials_updated_cb) { - service_controller_->UpdateRemotePublicCredentials( + service_controller_.UpdateRemotePublicCredentials( manager_app_id, account_name, remote_public_creds, std::move(credentials_updated_cb)); } diff --git a/presence/presence_service_impl.h b/presence/presence_service_impl.h index 76dc6e86..c39cc4f4 100644 --- a/presence/presence_service_impl.h +++ b/presence/presence_service_impl.h @@ -19,17 +19,24 @@ #include #include +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" #include "internal/platform/borrowable.h" +#include "internal/platform/implementation/credential_callbacks.h" +#include "internal/platform/single_thread_executor.h" #include "internal/proto/metadata.pb.h" +#include "presence/broadcast_request.h" #include "presence/data_types.h" #include "presence/implementation/broadcast_manager.h" +#include "presence/implementation/connection_authenticator_impl.h" #include "presence/implementation/credential_manager_impl.h" #include "presence/implementation/mediums/mediums.h" #include "presence/implementation/scan_manager.h" -#include "presence/implementation/service_controller.h" +#include "presence/implementation/service_controller_impl.h" #include "presence/presence_client.h" #include "presence/presence_device_provider.h" #include "presence/presence_service.h" +#include "presence/scan_request.h" namespace nearby { namespace presence { @@ -41,7 +48,7 @@ namespace presence { */ class PresenceServiceImpl : public PresenceService { public: - PresenceServiceImpl(); + PresenceServiceImpl() = default; ~PresenceServiceImpl() override { lender_.Release(); } std::unique_ptr CreatePresenceClient() override; @@ -63,11 +70,11 @@ class PresenceServiceImpl : public PresenceService { GenerateCredentialsResultCallback credentials_generated_cb) override; PresenceDeviceProvider* GetLocalDeviceProvider() override { - return provider_.get(); + return &provider_; } ::nearby::internal::Metadata GetLocalDeviceMetadata() override { - return service_controller_->GetLocalDeviceMetadata(); + return service_controller_.GetLocalDeviceMetadata(); } void GetLocalPublicCredentials( @@ -86,9 +93,12 @@ class PresenceServiceImpl : public PresenceService { CredentialManagerImpl credential_manager_{&executor_}; ScanManager scan_manager_{mediums_, credential_manager_, executor_}; BroadcastManager broadcast_manager_{mediums_, credential_manager_, executor_}; - std::unique_ptr service_controller_; + ServiceControllerImpl service_controller_{ + &executor_, &credential_manager_, &scan_manager_, &broadcast_manager_}; + ConnectionAuthenticatorImpl connection_authenticator_; ::nearby::Lender lender_{this}; - std::unique_ptr provider_; + PresenceDeviceProvider provider_{&service_controller_, + &connection_authenticator_}; }; } // namespace presence