diff --git a/internal/proto/credential.proto b/internal/proto/credential.proto index ec035248c1..264a78aea6 100644 --- a/internal/proto/credential.proto +++ b/internal/proto/credential.proto @@ -62,7 +62,7 @@ message SharedCredential { bytes encrypted_metadata_bytes_v0 = 5; // The tag for verifying metadata_encryption_key for a V0 advertisement. - bytes metadata_encryption_key_tag_v0 = 6; + bytes identity_token_tag_v0 = 6; // The public key is used to create a secure connection with the device. bytes connection_signature_verification_key = 7; diff --git a/internal/proto/local_credential.proto b/internal/proto/local_credential.proto index e1f63b0db8..1c46098d22 100644 --- a/internal/proto/local_credential.proto +++ b/internal/proto/local_credential.proto @@ -56,7 +56,7 @@ message LocalCredential { int64 end_time_millis = 4; // The 14 bytes aes key to encrypt metadata in PublicCredential. - bytes metadata_encryption_key_v0 = 5; + bytes identity_token_v0 = 5; // It is used for signing advertisement. PrivateKey advertisement_signing_key = 6; diff --git a/presence/broadcast_request.h b/presence/broadcast_request.h index 598ffdf35a..43c3daa356 100644 --- a/presence/broadcast_request.h +++ b/presence/broadcast_request.h @@ -18,7 +18,6 @@ #include #include -#include "absl/types/variant.h" #include "internal/proto/credential.pb.h" #include "presence/data_element.h" #include "presence/power_mode.h" @@ -26,8 +25,8 @@ namespace nearby { namespace presence { -// Broadcast parameter for presence features. -struct PresenceBroadcast { +// Nearby Presence advertisement request options. +struct BroadcastRequest { struct BroadcastSection { // Presence identity type. ::nearby::internal::IdentityType identity = @@ -52,16 +51,6 @@ struct PresenceBroadcast { std::string manager_app_id; }; - std::vector sections; -}; - -// Broadcast request for legacy Android T, which needs to provide credential -// and salt in the broadcast parameters. -// TODO(b/243443813) - Support Legacy Broadcast Request -struct LegacyPresenceBroadcast {}; - -// Nearby Presence advertisement request options. -struct BroadcastRequest { // Calibrated TX power. The broadcast recipient uses it to calculate the // distance between both devices. int tx_power; @@ -69,7 +58,7 @@ struct BroadcastRequest { // The broadcast frequency hint. PowerMode power_mode; - absl::variant variant; + std::vector sections; }; } // namespace presence diff --git a/presence/implementation/BUILD b/presence/implementation/BUILD index 40cd72389d..5b09b76a64 100644 --- a/presence/implementation/BUILD +++ b/presence/implementation/BUILD @@ -18,7 +18,6 @@ filegroup( name = "presence_internal_common_srcs", srcs = [ "action_factory.cc", - "advertisement_factory.cc", "advertisement_filter.cc", "base_broadcast_request.cc", "broadcast_manager.cc", @@ -36,7 +35,6 @@ filegroup( "action_factory.h", "advertisement_decoder.h", "advertisement_decoder_impl.h", - "advertisement_factory.h", "advertisement_filter.h", "base_broadcast_request.h", "broadcast_manager.h", @@ -55,10 +53,12 @@ cc_library( name = "internal", srcs = [ "advertisement_decoder_rust_impl.cc", + "advertisement_factory.cc", ":presence_internal_common_srcs", ], hdrs = [ "advertisement_decoder_rust_impl.h", + "advertisement_factory.h", ":presence_internal_common_hdrs", ], defines = ["USE_RUST_DECODER=1"], @@ -106,10 +106,12 @@ cc_library( name = "internal_deprecated", srcs = [ "advertisement_decoder_impl.cc", + "advertisement_factory_deprecated.cc", ":presence_internal_common_srcs", ], hdrs = [ "advertisement_decoder_impl.h", + "advertisement_factory_deprecated.h", ":presence_internal_common_hdrs", ], visibility = [ @@ -272,10 +274,10 @@ cc_test( "//internal/proto:credential_cc_proto", "//presence:types", "//presence/implementation/mediums", - "@com_github_protobuf_matchers//protobuf-matchers", + "//testing/base/public:gunit_main_no_googleheapcheck", "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", - "@com_google_googletest//:gtest_main", ] + select({ "@platforms//os:windows": [ "//internal/platform/implementation/windows", @@ -296,9 +298,12 @@ cc_test( "//internal/platform:test_util", "//internal/platform:types", "//internal/proto:credential_cc_proto", + "//presence:types", "//presence/implementation/mediums", - "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_googletest//:gtest_main", + "//testing/base/public:gunit_main_no_googleheapcheck", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings:string_view", ] + select({ "@platforms//os:windows": [ "//internal/platform/implementation/windows", @@ -338,6 +343,8 @@ cc_test( "//internal/proto:credential_cc_proto", "//presence:types", "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/types:variant", "@com_google_googletest//:gtest_main", ] + select({ diff --git a/presence/implementation/action_factory.cc b/presence/implementation/action_factory.cc index 050a29c524..3362c1baf4 100644 --- a/presence/implementation/action_factory.cc +++ b/presence/implementation/action_factory.cc @@ -15,10 +15,12 @@ #include "presence/implementation/action_factory.h" #include +#include #include -#include "absl/types/optional.h" #include "internal/platform/logging.h" +#include "presence/data_element.h" +#include "presence/implementation/base_broadcast_request.h" namespace nearby { namespace presence { diff --git a/presence/implementation/advertisement_decoder_impl.cc b/presence/implementation/advertisement_decoder_impl.cc index b4138add61..335dba0e47 100644 --- a/presence/implementation/advertisement_decoder_impl.cc +++ b/presence/implementation/advertisement_decoder_impl.cc @@ -44,7 +44,7 @@ constexpr uint8_t kDataTypeMask = constexpr int kAdvertisementVersion = 0; constexpr int kEncryptedIdentityAdditionalLength = - kSaltSize + kBaseMetadataSize; + kSaltSize + kV0IdentityTokenSize; constexpr int kEddystoneAdditionalLength = 20; uint8_t GetDataElementType(uint8_t header) { return header & kDataTypeMask; } @@ -181,15 +181,15 @@ absl::StatusOr DecryptLdt( } for (const auto& credential : credentials) { absl::StatusOr encryptor = LdtEncryptor::Create( - credential.key_seed(), credential.metadata_encryption_key_tag_v0()); + credential.key_seed(), credential.identity_token_tag_v0()); if (encryptor.ok()) { absl::StatusOr result = encryptor->DecryptAndVerify(encrypted_contents, salt); - if (result.ok() && result->size() > kBaseMetadataSize) { + if (result.ok() && result->size() > kV0IdentityTokenSize) { decoded_advertisement.public_credential = credential; decoded_advertisement.metadata_key = - result->substr(0, kBaseMetadataSize); - return result->substr(kBaseMetadataSize); + result->substr(0, kV0IdentityTokenSize); + return result->substr(kV0IdentityTokenSize); } } } diff --git a/presence/implementation/advertisement_decoder_new_format_test.cc b/presence/implementation/advertisement_decoder_new_format_test.cc index 6225111a2a..ec31ec14c1 100644 --- a/presence/implementation/advertisement_decoder_new_format_test.cc +++ b/presence/implementation/advertisement_decoder_new_format_test.cc @@ -87,7 +87,7 @@ TEST(AdvertisementDecoderImpl, DecodeEncryptedAdvertisement) { 0xB8, 0xEA, 0x67, 0xD1, 0x1C, 0x3E, 0x36, 0xFD}); SharedCredential public_credential; public_credential.set_key_seed(seed.AsStringView()); - public_credential.set_metadata_encryption_key_tag_v0( + public_credential.set_identity_token_tag_v0( known_mac.AsStringView()); absl::flat_hash_map> credentials; diff --git a/presence/implementation/advertisement_decoder_rust_impl.cc b/presence/implementation/advertisement_decoder_rust_impl.cc index cbe2b5f75b..914acbe543 100644 --- a/presence/implementation/advertisement_decoder_rust_impl.cc +++ b/presence/implementation/advertisement_decoder_rust_impl.cc @@ -202,7 +202,7 @@ AdvertisementDecoderImpl::InitializeCredentialBook( std::array key_seed_array; std::copy(key_seed.begin(), key_seed.end(), key_seed_array.data()); - auto tag = credential.metadata_encryption_key_tag_v0(); + auto tag = credential.identity_token_tag_v0(); std::array tag_array; std::copy(tag.begin(), tag.end(), tag_array.data()); diff --git a/presence/implementation/advertisement_decoder_test.cc b/presence/implementation/advertisement_decoder_test.cc index 5b2a70d473..798f0d5ea9 100644 --- a/presence/implementation/advertisement_decoder_test.cc +++ b/presence/implementation/advertisement_decoder_test.cc @@ -76,8 +76,7 @@ SharedCredential GetPublicCredential() { 0xCA, 0x25, 0x4C, 0x35, 0x54, 0xDC, 0xE5, 0x0E}); SharedCredential public_credential; public_credential.set_key_seed(seed.AsStringView()); - public_credential.set_metadata_encryption_key_tag_v0( - known_mac.AsStringView()); + public_credential.set_identity_token_tag_v0(known_mac.AsStringView()); return public_credential; } diff --git a/presence/implementation/advertisement_factory.cc b/presence/implementation/advertisement_factory.cc index 2bdb5d13a9..a90e11491a 100644 --- a/presence/implementation/advertisement_factory.cc +++ b/presence/implementation/advertisement_factory.cc @@ -14,27 +14,22 @@ #include "presence/implementation/advertisement_factory.h" -#include +#include +#include #include #include -#include #include -#include "absl/base/attributes.h" #include "absl/status/status.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" -#include "absl/types/variant.h" +#include "nearby_protocol.h" #include "internal/platform/implementation/credential_callbacks.h" #include "internal/platform/logging.h" -#include "internal/platform/uuid.h" #include "internal/proto/credential.pb.h" #include "presence/data_element.h" #include "presence/implementation/base_broadcast_request.h" -#include "presence/implementation/ldt.h" #include "presence/implementation/mediums/advertisement_data.h" namespace nearby { @@ -43,194 +38,172 @@ namespace presence { namespace { using ::nearby::internal::IdentityType; constexpr uint8_t kBaseVersion = 0; -constexpr size_t kMaxBaseNpAdvSize = 26; -absl::StatusOr CreateDataElementHeader(size_t length, - unsigned data_type) { - if (length > DataElement::kMaxDataElementLength) { - return absl::InvalidArgumentError( - absl::StrFormat("Unsupported Data Element length: %d", length)); - } - if (data_type > DataElement::kMaxDataElementType) { - return absl::InvalidArgumentError( - absl::StrFormat("Unsupported Data Element type: %d", data_type)); - } - return (length << DataElement::kDataElementLengthShift) | data_type; +bool IsEncryptedAdvertisement(IdentityType identity_type) { + return identity_type == IdentityType::IDENTITY_TYPE_PRIVATE_GROUP || + identity_type == IdentityType::IDENTITY_TYPE_CONTACTS_GROUP; } -absl::Status AppendDataElement(unsigned data_type, - absl::string_view data_element, - std::string& output) { - auto header = CreateDataElementHeader(data_element.size(), data_type); - if (!header.ok()) { - NEARBY_LOG(WARNING, "Can't add Data element type: %d, length: %d", - data_type, data_element.size()); - return header.status(); - } - output.push_back(*header); - output.insert(output.end(), data_element.begin(), data_element.end()); - return absl::OkStatus(); +absl::StatusOr +CreateV0BroadcastCredential(std::string key_seed, std::string identity_token) { + std::array key_seed_bytes; + std::copy(key_seed.begin(), key_seed.end(), key_seed_bytes.data()); + + std::array identity_token_bytes; + std::copy(identity_token.begin(), identity_token.end(), + identity_token_bytes.data()); + + return nearby_protocol::V0BroadcastCredential(key_seed_bytes, + identity_token_bytes); } -uint8_t GetIdentityFieldType(IdentityType type) { - switch (type) { - case IdentityType::IDENTITY_TYPE_PRIVATE_GROUP: - return DataElement::kPrivateGroupIdentityFieldType; - case IdentityType::IDENTITY_TYPE_CONTACTS_GROUP: - return DataElement::kContactsGroupIdentityFieldType; - case IdentityType::IDENTITY_TYPE_PUBLIC: - ABSL_FALLTHROUGH_INTENDED; +absl::StatusOr MapAction(const ActionBit action) { + switch (action) { + case ActionBit::kActiveUnlockAction: + return nearby_protocol::ActionType::ActiveUnlock; + case ActionBit::kNearbyShareAction: + return nearby_protocol::ActionType::NearbyShare; + case ActionBit::kInstantTetheringAction: + return nearby_protocol::ActionType::InstantTethering; + case ActionBit::kPhoneHubAction: + return nearby_protocol::ActionType::PhoneHub; default: - return DataElement::kPublicIdentityFieldType; + return absl::InvalidArgumentError("Unsupported action type"); } } -std::string SerializeAction(const Action& action) { - std::string output; - uint32_t input = action.action; - for (int i = 3; i >= 0; --i) { - if (input == 0) { - return output; +nearby_protocol::V0DataElement CreateActionsDataElement( + const std::vector data_elements, + nearby_protocol::AdvertisementBuilderKind kind) { + auto actions = nearby_protocol::V0Actions::BuildNewZeroed(kind); + for (const auto& data_element : data_elements) { + if (data_element.GetType() == data_element.kActionFieldType) { + auto action = static_cast(data_element.GetValue()[0]); + auto action_type = MapAction(action); + if (!action_type.ok()) { + NEARBY_LOGS(WARNING) + << "Unsupported action type, is not being added to the broadcast: " + << (int)action; + continue; + } + auto result = actions.TrySetAction(*action_type, true); + if (!result.ok()) { + auto kind_string = + (kind == nearby_protocol::AdvertisementBuilderKind::Public) + ? "Plaintext" + : "Encrypted"; + NEARBY_LOGS(WARNING) << "Provided action type is not supported for " + "given advertisement type: " + << kind_string << " action:" << (int)action; + continue; + } } - int shift = 8 * i; - output.push_back(static_cast((input >> shift) & 0xFF)); - input &= (1 << shift) - 1; } - return output; + return nearby_protocol::V0DataElement(actions); } -bool RequiresCredentials(IdentityType identity_type) { - return identity_type == IdentityType::IDENTITY_TYPE_PRIVATE_GROUP || - identity_type == IdentityType::IDENTITY_TYPE_CONTACTS_GROUP; -} -} // namespace +absl::StatusOr CreateEncryptedAdvertisement( + const BaseBroadcastRequest& request, internal::LocalCredential credential) { + if (request.salt.size() != kSaltSize) { + return absl::InvalidArgumentError( + absl::StrFormat("Unsupported salt size %d", request.salt.size())); + } + std::array salt; + std::copy(request.salt.begin(), request.salt.end(), salt.data()); -absl::StatusOr AdvertisementFactory::CreateAdvertisement( - const BaseBroadcastRequest& request, - absl::optional credential) const { - AdvertisementData advert = {}; - if (absl::holds_alternative( - request.variant)) { - return CreateBaseNpAdvertisement(request, std::move(credential)); + auto broadcast_credential = CreateV0BroadcastCredential( + credential.key_seed(), credential.identity_token_v0()); + if (!broadcast_credential.ok()) { + return broadcast_credential.status(); } - return advert; -} -absl::StatusOr -AdvertisementFactory::CreateBaseNpAdvertisement( - const BaseBroadcastRequest& request, - absl::optional credential) const { - const auto& presence = - absl::get(request.variant); - std::string payload; - payload.reserve(kMaxBaseNpAdvSize); - payload.push_back(kBaseVersion); - absl::Status result; - std::string tx_power = {static_cast(request.tx_power)}; - std::string action = SerializeAction(presence.action); - uint8_t identity_type = - GetIdentityFieldType(presence.credential_selector.identity_type); - bool needs_encryption = - identity_type != DataElement::kPublicIdentityFieldType; - if (needs_encryption) { - if (request.salt.size() != kSaltSize) { - return absl::InvalidArgumentError( - absl::StrFormat("Unsupported salt size %d", request.salt.size())); - } - if (!credential) { - return absl::FailedPreconditionError("Missing credentials"); - } - std::string unencrypted; - result = AppendDataElement(DataElement::kTxPowerFieldType, tx_power, - unencrypted); - if (!result.ok()) { - return result; - } - result = - AppendDataElement(DataElement::kActionFieldType, action, unencrypted); - if (!result.ok()) { - return result; - } - NEARBY_LOGS(VERBOSE) << "Unencrypted advertisement payload " - << absl::BytesToHexString(unencrypted); - absl::StatusOr encrypted = - EncryptDataElements(*credential, request.salt, unencrypted); - if (!encrypted.ok()) { - return encrypted.status(); - } - if (encrypted->size() <= kBaseMetadataSize) { - return absl::OutOfRangeError( - absl::StrFormat("Encrypted identity DE is too short - %d bytes. " - "Expected more than %d", - encrypted->size(), kBaseMetadataSize)); - } + auto adv_builder = nearby_protocol::V0AdvertisementBuilder::CreateEncrypted( + *broadcast_credential, salt); - // The Identity DE header does not include the length of salt nor metadata. - absl::StatusOr identity_header = CreateDataElementHeader( - encrypted->size() - kBaseMetadataSize, identity_type); - if (!identity_header.ok()) { - return identity_header.status(); - } - payload.push_back(*identity_header); - // In the encrypted format, salt is not a DE (thus no header) - payload.append(request.salt); - payload.append(*encrypted); - } else { - result = AppendDataElement(identity_type, "", payload); - if (!result.ok()) { - return result; - } - if (!request.salt.empty()) { - result = - AppendDataElement(DataElement::kSaltFieldType, request.salt, payload); - if (!result.ok()) { - return result; - } - } - result = - AppendDataElement(DataElement::kTxPowerFieldType, tx_power, payload); - if (!result.ok()) { - return result; - } - result = AppendDataElement(DataElement::kActionFieldType, action, payload); - if (!result.ok()) { - return result; + auto tx_power = nearby_protocol::TxPower::TryBuildFromI8(request.tx_power); + if (!tx_power.ok()) { + return tx_power.status(); + } + + auto tx_power_data_element = nearby_protocol::V0DataElement(tx_power.value()); + auto result = adv_builder.TryAddDE(tx_power_data_element); + if (!result.ok()) { + return result; + } + + if (!request.data_elements.empty()) { + auto actions_data_element = CreateActionsDataElement( + request.data_elements, + nearby_protocol::AdvertisementBuilderKind::Encrypted); + auto add_de_result = adv_builder.TryAddDE(actions_data_element); + if (!add_de_result.ok()) { + return add_de_result; } } + + auto serialized_bytes = adv_builder.TrySerialize(); + if (!serialized_bytes.ok()) { + return serialized_bytes.status(); + } + return AdvertisementData{.is_extended_advertisement = false, - .content = payload}; + .content = serialized_bytes->ToString()}; } -absl::StatusOr AdvertisementFactory::EncryptDataElements( - const LocalCredential& credential, absl::string_view salt, - absl::string_view data_elements) const { - if (credential.metadata_encryption_key_v0().size() != kBaseMetadataSize) { - return absl::FailedPreconditionError(absl::StrFormat( - "Metadata key size %d, expected %d", - credential.metadata_encryption_key_v0().size(), kBaseMetadataSize)); + +absl::StatusOr CreateUnencryptedAdvertisement( + const BaseBroadcastRequest& request) { + auto adv_builder = nearby_protocol::V0AdvertisementBuilder::CreatePublic(); + + auto tx_power = nearby_protocol::TxPower::TryBuildFromI8(request.tx_power); + if (!tx_power.ok()) { + return tx_power.status(); + } + auto de = nearby_protocol::V0DataElement(*tx_power); + auto add_de_result = adv_builder.TryAddDE(de); + if (!add_de_result.ok()) { + return add_de_result; + } + + if (!request.data_elements.empty()) { + auto actions_data_element = CreateActionsDataElement( + request.data_elements, + nearby_protocol::AdvertisementBuilderKind::Public); + add_de_result = adv_builder.TryAddDE(actions_data_element); + if (!add_de_result.ok()) { + return add_de_result; + } + } + + auto serialized_bytes = adv_builder.TrySerialize(); + if (!serialized_bytes.ok()) { + return serialized_bytes.status(); } + return AdvertisementData{.is_extended_advertisement = false, + .content = serialized_bytes->ToString()}; +} + +} // namespace - // HMAC is not used during encryption, so we can pass an empty value. - absl::StatusOr encryptor = - LdtEncryptor::Create(credential.key_seed(), /*known_hmac=*/""); - if (!encryptor.ok()) { - return encryptor.status(); +absl::StatusOr AdvertisementFactory::CreateAdvertisement( + const BaseBroadcastRequest& request, + absl::optional credential) const { // NOLINT + if (IsEncryptedAdvertisement(request.credential_selector.identity_type)) { + if (!credential) { + return absl::FailedPreconditionError("Missing credentials"); + } + return CreateEncryptedAdvertisement(request, *credential); + } else { + return CreateUnencryptedAdvertisement(request); } - std::string plaintext = - absl::StrCat(credential.metadata_encryption_key_v0(), data_elements); - return encryptor->Encrypt(plaintext, salt); } absl::StatusOr AdvertisementFactory::GetCredentialSelector( const BaseBroadcastRequest& request) { - if (absl::holds_alternative( - request.variant)) { - const auto& presence = - absl::get(request.variant); - if (RequiresCredentials(presence.credential_selector.identity_type)) { - return presence.credential_selector; - } + if (IsEncryptedAdvertisement(request.credential_selector.identity_type)) { + return request.credential_selector; } return absl::NotFoundError("credentials not required"); } + } // namespace presence } // namespace nearby diff --git a/presence/implementation/advertisement_factory.h b/presence/implementation/advertisement_factory.h index 542119441d..e63b2b110f 100644 --- a/presence/implementation/advertisement_factory.h +++ b/presence/implementation/advertisement_factory.h @@ -15,10 +15,7 @@ #ifndef THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_FACTORY_H_ #define THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_FACTORY_H_ -#include - #include "absl/status/statusor.h" -#include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "internal/platform/implementation/credential_callbacks.h" #include "presence/implementation/base_broadcast_request.h" @@ -47,14 +44,6 @@ class AdvertisementFactory { return CreateAdvertisement(request, absl::optional()); // NOLINT } - - private: - absl::StatusOr CreateBaseNpAdvertisement( - const BaseBroadcastRequest& request, - absl::optional credential) const; // NOLINT - absl::StatusOr EncryptDataElements( - const LocalCredential& credential, absl::string_view salt, - absl::string_view data_elements) const; }; } // namespace presence diff --git a/presence/implementation/advertisement_factory_deprecated.cc b/presence/implementation/advertisement_factory_deprecated.cc new file mode 100644 index 0000000000..95ca54eb34 --- /dev/null +++ b/presence/implementation/advertisement_factory_deprecated.cc @@ -0,0 +1,198 @@ +// Copyright 2022 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. + +#include "presence/implementation/advertisement_factory_deprecated.h" + +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/status/status.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "internal/platform/implementation/credential_callbacks.h" +#include "internal/platform/logging.h" +#include "internal/proto/credential.pb.h" +#include "presence/data_element.h" +#include "presence/implementation/base_broadcast_request.h" +#include "presence/implementation/ldt.h" +#include "presence/implementation/mediums/advertisement_data.h" + +namespace nearby { +namespace presence { + +namespace { +using ::nearby::internal::IdentityType; +constexpr uint8_t kBaseVersion = 0; +constexpr size_t kMaxBaseNpAdvSize = 26; + +absl::StatusOr CreateDataElementHeader(size_t length, + unsigned data_type) { + if (length > DataElement::kMaxDataElementLength) { + return absl::InvalidArgumentError( + absl::StrFormat("Unsupported Data Element length: %d", length)); + } + if (data_type > DataElement::kMaxDataElementType) { + return absl::InvalidArgumentError( + absl::StrFormat("Unsupported Data Element type: %d", data_type)); + } + return (length << DataElement::kDataElementLengthShift) | data_type; +} + +absl::Status AppendDataElement(unsigned data_type, + absl::string_view data_element, + std::string& output) { + auto header = CreateDataElementHeader(data_element.size(), data_type); + if (!header.ok()) { + NEARBY_LOG(WARNING, "Can't add Data element type: %d, length: %d", + data_type, data_element.size()); + return header.status(); + } + output.push_back(*header); + output.insert(output.end(), data_element.begin(), data_element.end()); + return absl::OkStatus(); +} + +uint8_t GetIdentityFieldType(IdentityType type) { + switch (type) { + case IdentityType::IDENTITY_TYPE_PRIVATE_GROUP: + return DataElement::kPrivateGroupIdentityFieldType; + case IdentityType::IDENTITY_TYPE_CONTACTS_GROUP: + return DataElement::kContactsGroupIdentityFieldType; + case IdentityType::IDENTITY_TYPE_PUBLIC: + ABSL_FALLTHROUGH_INTENDED; + default: + return DataElement::kPublicIdentityFieldType; + } +} + +bool RequiresCredentials(IdentityType identity_type) { + return identity_type == IdentityType::IDENTITY_TYPE_PRIVATE_GROUP || + identity_type == IdentityType::IDENTITY_TYPE_CONTACTS_GROUP; +} +} // namespace + +absl::StatusOr AdvertisementFactory::CreateAdvertisement( + const BaseBroadcastRequest& request, + absl::optional credential) const { // NOLINT + AdvertisementData advert = {}; + return CreateBaseNpAdvertisement(request, std::move(credential)); +} + +absl::StatusOr +AdvertisementFactory::CreateBaseNpAdvertisement( + const BaseBroadcastRequest& request, + absl::optional credential) const { // NOLINT + std::string payload; + payload.reserve(kMaxBaseNpAdvSize); + payload.push_back(kBaseVersion); + absl::Status result; + std::string tx_power = {static_cast(request.tx_power)}; + uint8_t identity_type = + GetIdentityFieldType(request.credential_selector.identity_type); + bool needs_encryption = + identity_type != DataElement::kPublicIdentityFieldType; + if (needs_encryption) { + if (request.salt.size() != kSaltSize) { + return absl::InvalidArgumentError( + absl::StrFormat("Unsupported salt size %d", request.salt.size())); + } + if (!credential) { + return absl::FailedPreconditionError("Missing credentials"); + } + std::string unencrypted; + result = AppendDataElement(DataElement::kTxPowerFieldType, tx_power, + unencrypted); + if (!result.ok()) { + return result; + } + NEARBY_LOGS(VERBOSE) << "Unencrypted advertisement payload " + << absl::BytesToHexString(unencrypted); + absl::StatusOr encrypted = + EncryptDataElements(*credential, request.salt, unencrypted); + if (!encrypted.ok()) { + return encrypted.status(); + } + if (encrypted->size() <= kV0IdentityTokenSize) { + return absl::OutOfRangeError( + absl::StrFormat("Encrypted identity DE is too short - %d bytes. " + "Expected more than %d", + encrypted->size(), kV0IdentityTokenSize)); + } + + // The Identity DE header does not include the length of salt nor metadata. + absl::StatusOr identity_header = CreateDataElementHeader( + encrypted->size() - kV0IdentityTokenSize, identity_type); + if (!identity_header.ok()) { + return identity_header.status(); + } + payload.push_back(*identity_header); + // In the encrypted format, salt is not a DE (thus no header) + payload.append(request.salt); + payload.append(*encrypted); + } else { + result = AppendDataElement(identity_type, "", payload); + if (!result.ok()) { + return result; + } + if (!request.salt.empty()) { + result = + AppendDataElement(DataElement::kSaltFieldType, request.salt, payload); + if (!result.ok()) { + return result; + } + } + result = + AppendDataElement(DataElement::kTxPowerFieldType, tx_power, payload); + if (!result.ok()) { + return result; + } + } + return AdvertisementData{.is_extended_advertisement = false, + .content = payload}; +} +absl::StatusOr AdvertisementFactory::EncryptDataElements( + const LocalCredential& credential, absl::string_view salt, + absl::string_view data_elements) const { + if (credential.identity_token_v0().size() != kV0IdentityTokenSize) { + return absl::FailedPreconditionError(absl::StrFormat( + "Metadata key size %d, expected %d", + credential.identity_token_v0().size(), kV0IdentityTokenSize)); + } + + // HMAC is not used during encryption, so we can pass an empty value. + absl::StatusOr encryptor = + LdtEncryptor::Create(credential.key_seed(), /*known_hmac=*/""); + if (!encryptor.ok()) { + return encryptor.status(); + } + std::string plaintext = + absl::StrCat(credential.identity_token_v0(), data_elements); + return encryptor->Encrypt(plaintext, salt); +} + +absl::StatusOr AdvertisementFactory::GetCredentialSelector( + const BaseBroadcastRequest& request) { + if (RequiresCredentials(request.credential_selector.identity_type)) { + return request.credential_selector; + } + return absl::NotFoundError("credentials not required"); +} +} // namespace presence +} // namespace nearby diff --git a/presence/implementation/advertisement_factory_deprecated.h b/presence/implementation/advertisement_factory_deprecated.h new file mode 100644 index 0000000000..0333f72b83 --- /dev/null +++ b/presence/implementation/advertisement_factory_deprecated.h @@ -0,0 +1,63 @@ +// Copyright 2022 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_ADVERTISEMENT_FACTORY_DEPRECATED_H_ +#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_FACTORY_DEPRECATED_H_ + +#include + +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "internal/platform/implementation/credential_callbacks.h" +#include "presence/implementation/base_broadcast_request.h" +#include "presence/implementation/mediums/advertisement_data.h" + +namespace nearby { +namespace presence { + +// Builds BLE advertisements from broadcast requests. +class AdvertisementFactory { + public: + using LocalCredential = internal::LocalCredential; + + // Returns a `CredentialSelector` if credentials are required to create an + // advertisement from the `request`. + static absl::StatusOr GetCredentialSelector( + const BaseBroadcastRequest& request); + + // Returns a BLE advertisement for given `request. + absl::StatusOr CreateAdvertisement( + const BaseBroadcastRequest& request, + absl::optional credential) const; // NOLINT + + absl::StatusOr CreateAdvertisement( + const BaseBroadcastRequest& request) const { + return CreateAdvertisement(request, + absl::optional()); // NOLINT + } + + private: + absl::StatusOr CreateBaseNpAdvertisement( + const BaseBroadcastRequest& request, + absl::optional credential) const; // NOLINT + absl::StatusOr EncryptDataElements( + const LocalCredential& credential, absl::string_view salt, + absl::string_view data_elements) const; +}; + +} // namespace presence +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_FACTORY_DEPRECATED_H_ diff --git a/presence/implementation/advertisement_factory_test.cc b/presence/implementation/advertisement_factory_test.cc index 8c2897f892..664fa20450 100644 --- a/presence/implementation/advertisement_factory_test.cc +++ b/presence/implementation/advertisement_factory_test.cc @@ -21,11 +21,12 @@ #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/escaping.h" #include "internal/platform/byte_array.h" #include "internal/proto/credential.pb.h" #include "presence/data_element.h" -#include "presence/implementation/action_factory.h" +#include "presence/implementation/base_broadcast_request.h" #include "presence/implementation/mediums/advertisement_data.h" namespace nearby { @@ -36,8 +37,6 @@ namespace { using ::nearby::ByteArray; // NOLINT using ::nearby::internal::IdentityType; using ::nearby::internal::LocalCredential; // NOLINT -using ::testing::NiceMock; -using ::testing::Return; using ::testing::status::StatusIs; LocalCredential CreateLocalCredential(IdentityType identity_type) { @@ -51,8 +50,7 @@ LocalCredential CreateLocalCredential(IdentityType identity_type) { LocalCredential private_credential; private_credential.set_identity_type(identity_type); private_credential.set_key_seed(seed.AsStringView()); - private_credential.set_metadata_encryption_key_v0( - metadata_key.AsStringView()); + private_credential.set_identity_token_v0(metadata_key.AsStringView()); return private_credential; } @@ -62,13 +60,13 @@ TEST(AdvertisementFactory, CreateAdvertisementFromPrivateIdentity) { constexpr IdentityType kIdentity = IdentityType::IDENTITY_TYPE_PRIVATE_GROUP; std::vector data_elements; data_elements.emplace_back(ActionBit::kActiveUnlockAction); - Action action = ActionFactory::CreateAction(data_elements); + BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) .SetAccountName(account_name) .SetSalt(salt) .SetTxPower(5) - .SetAction(action)); + .SetActions(data_elements)); absl::StatusOr result = AdvertisementFactory().CreateAdvertisement( @@ -77,7 +75,7 @@ TEST(AdvertisementFactory, CreateAdvertisementFromPrivateIdentity) { ASSERT_OK(result); EXPECT_FALSE(result->is_extended_advertisement); EXPECT_EQ(absl::BytesToHexString(result->content), - "00514142b8412efb0bc657ba514baf4d1b50ddc842cd1c"); + "044142b8412efb0bc657ba514baf4d1b50ddc842cd1c"); } TEST(AdvertisementFactory, CreateAdvertisementFromTrustedIdentity) { @@ -87,13 +85,12 @@ TEST(AdvertisementFactory, CreateAdvertisementFromTrustedIdentity) { std::vector data_elements; data_elements.emplace_back(ActionBit::kActiveUnlockAction); data_elements.emplace_back(ActionBit::kPresenceManagerAction); - Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) .SetAccountName(account_name) .SetSalt(salt) .SetTxPower(5) - .SetAction(action)); + .SetActions(data_elements)); absl::StatusOr result = AdvertisementFactory().CreateAdvertisement( @@ -102,7 +99,7 @@ TEST(AdvertisementFactory, CreateAdvertisementFromTrustedIdentity) { ASSERT_OK(result); EXPECT_FALSE(result->is_extended_advertisement); EXPECT_EQ(absl::BytesToHexString(result->content), - "0052414257a35c020f1c547d7e169303196d75da7118ba"); + "044142b8412efb0bc657ba514baf4d1b50ddc842cd1c"); } TEST(AdvertisementFactory, CreateAdvertisementFromPublicIdentity) { @@ -110,36 +107,78 @@ TEST(AdvertisementFactory, CreateAdvertisementFromPublicIdentity) { constexpr IdentityType kIdentity = IdentityType::IDENTITY_TYPE_PUBLIC; std::vector data_elements; data_elements.emplace_back(ActionBit::kActiveUnlockAction); - Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) .SetSalt(salt) .SetTxPower(5) - .SetAction(action)); + .SetActions(data_elements)); absl::StatusOr result = AdvertisementFactory().CreateAdvertisement(request); ASSERT_OK(result); EXPECT_FALSE(result->is_extended_advertisement); - EXPECT_EQ(absl::BytesToHexString(result->content), "00032041421505260080"); + EXPECT_EQ(absl::BytesToHexString(result->content), "0015051600"); } -TEST(AdvertisementFactory, CreateAdvertisementFailsWhenSaltIsTooShort) { +TEST(AdvertisementFactory, V0PrivateIdentitySerializationSimpleCase) { + std::string salt = absl::HexStringToBytes("2222"); + std::string identity_token = + absl::HexStringToBytes("3333333333333333333333333333"); + std::string key_seed = absl::HexStringToBytes( + "1111111111111111111111111111111111111111111111111111111111111111"); + + LocalCredential private_credential; + private_credential.set_identity_type( + IdentityType::IDENTITY_TYPE_PRIVATE_GROUP); + private_credential.set_key_seed(key_seed); + private_credential.set_identity_token_v0(identity_token); + + BaseBroadcastRequest request = BaseBroadcastRequest( + BasePresenceRequestBuilder(IdentityType::IDENTITY_TYPE_PRIVATE_GROUP) + .SetSalt(salt) + .SetTxPower(3)); + + absl::StatusOr result = + AdvertisementFactory().CreateAdvertisement(request, private_credential); + + ASSERT_OK(result); + + // V0 encrypted advertisement data - ripped out of + // //third_party/beto_core/nearby/presence/np_adv/tests/examples_v0.rs + EXPECT_EQ(absl::BytesToHexString(result->content), + "042222d82212ef16dbf872f2a3a7c0fa5248ec"); +} + +TEST(AdvertisementFactory, CreateAdvertisementMissingCredentials) { std::string salt = "AB"; constexpr IdentityType kIdentity = internal::IDENTITY_TYPE_PRIVATE_GROUP; std::vector data_elements; data_elements.emplace_back(ActionBit::kActiveUnlockAction); - Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) .SetSalt(salt) .SetTxPower(5) - .SetAction(action)); - // Override the salt with invalid value - request.salt = "C"; + .SetActions(data_elements)); EXPECT_THAT(AdvertisementFactory().CreateAdvertisement(request), + StatusIs(absl::StatusCode::kFailedPrecondition)); +} + +TEST(AdvertisementFactory, CreateAdvertisementInvalidSalt) { + std::string salt = "AB"; + constexpr IdentityType kIdentity = internal::IDENTITY_TYPE_PRIVATE_GROUP; + std::vector data_elements; + data_elements.emplace_back(ActionBit::kActiveUnlockAction); + BaseBroadcastRequest request = + BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) + .SetSalt(salt) + .SetTxPower(5) + .SetActions(data_elements)); + // Override the salt with invalid value + request.salt = "C"; + auto credential = CreateLocalCredential(kIdentity); + EXPECT_THAT(AdvertisementFactory().CreateAdvertisement(request, credential), StatusIs(absl::StatusCode::kInvalidArgument)); } diff --git a/presence/implementation/base_broadcast_request.cc b/presence/implementation/base_broadcast_request.cc index ffac5df4c8..04e1c9ce62 100644 --- a/presence/implementation/base_broadcast_request.cc +++ b/presence/implementation/base_broadcast_request.cc @@ -14,15 +14,17 @@ #include "presence/implementation/base_broadcast_request.h" +#include #include -#include +#include #include "absl/status/status.h" #include "absl/strings/string_view.h" #include "internal/platform/implementation/crypto.h" #include "internal/platform/logging.h" #include "presence/broadcast_request.h" -#include "presence/implementation/action_factory.h" +#include "presence/data_element.h" +#include "presence/power_mode.h" namespace nearby { namespace presence { @@ -42,9 +44,9 @@ BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetTxPower( return *this; } -BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetAction( - const Action& action) { - action_ = action; +BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetActions( + std::vector data_elements) { + data_elements_ = data_elements; return *this; } @@ -67,17 +69,17 @@ BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetManagerAppId( } BasePresenceRequestBuilder::operator BaseBroadcastRequest() const { - BaseBroadcastRequest::BasePresence presence{ - .credential_selector = {.manager_app_id = manager_app_id_, - .account_name = account_name_, - .identity_type = identity_}, - .action = action_}; - std::string bytes(kSaltSize, 0); RandBytes(const_cast(bytes.data()), bytes.size()); BaseBroadcastRequest broadcast_request{ - .variant = presence, + .credential_selector = + { + .manager_app_id = manager_app_id_, + .account_name = account_name_, + .identity_type = identity_, + }, + .data_elements = data_elements_, .salt = salt_.size() == kSaltSize ? salt_ : bytes, .tx_power = tx_power_, .power_mode = power_mode_}; @@ -86,27 +88,19 @@ BasePresenceRequestBuilder::operator BaseBroadcastRequest() const { absl::StatusOr BaseBroadcastRequest::Create( const BroadcastRequest& request) { - if (absl::holds_alternative(request.variant)) { - const auto& presence_request = - absl::get(request.variant); - if (presence_request.sections.empty()) { - return absl::InvalidArgumentError("Missing broadcast sections"); - } - if (presence_request.sections.size() > 1) { - NEARBY_LOG(WARNING, - "Only first section is used in BLE 4.2 advertisement"); - } - const PresenceBroadcast::BroadcastSection& section = - presence_request.sections.front(); - return BaseBroadcastRequest( - BasePresenceRequestBuilder(section.identity) - .SetTxPower(request.tx_power) - .SetAction(ActionFactory::CreateAction(section.extended_properties)) - .SetPowerMode(request.power_mode) - .SetManagerAppId(section.manager_app_id) - .SetAccountName(section.account_name)); + if (request.sections.empty()) { + return absl::InvalidArgumentError("Missing broadcast sections"); + } + if (request.sections.size() > 1) { + NEARBY_LOG(WARNING, "Only first section is used in BLE 4.2 advertisement"); } - return absl::UnimplementedError("Request not supported"); + const BroadcastRequest::BroadcastSection& section = request.sections.front(); + return BaseBroadcastRequest(BasePresenceRequestBuilder(section.identity) + .SetTxPower(request.tx_power) + .SetActions(section.extended_properties) + .SetPowerMode(request.power_mode) + .SetManagerAppId(section.manager_app_id) + .SetAccountName(section.account_name)); } } // namespace presence diff --git a/presence/implementation/base_broadcast_request.h b/presence/implementation/base_broadcast_request.h index 36821ccc71..41e8eb291c 100644 --- a/presence/implementation/base_broadcast_request.h +++ b/presence/implementation/base_broadcast_request.h @@ -19,12 +19,13 @@ #include #include +#include #include "absl/status/statusor.h" #include "absl/strings/string_view.h" -#include "absl/types/variant.h" #include "internal/platform/implementation/credential_callbacks.h" #include "presence/broadcast_request.h" +#include "presence/data_element.h" #include "presence/power_mode.h" namespace nearby { @@ -32,8 +33,9 @@ namespace presence { constexpr int8_t kUnspecifiedTxPower = -128; constexpr size_t kSaltSize = 2; + // The identity metadata size in the base advertisement -constexpr size_t kBaseMetadataSize = 14; +constexpr size_t kV0IdentityTokenSize = 14; /** Defines the action (intended actions) of base NP advertisement */ struct Action { @@ -47,24 +49,8 @@ struct BaseBroadcastRequest { static absl::StatusOr Create( const BroadcastRequest& request); - struct BasePresence { - CredentialSelector credential_selector; - Action action; - }; - struct BaseFastPair { - struct Discoverable { - std::string model_id; - }; - struct Nondiscoverable { - std::string account_key_data; - std::string battery_info; - }; - absl::variant advertisement; - }; - struct BaseEddystone { - std::string ephemeral_id; - }; - absl::variant variant; + CredentialSelector credential_selector; + std::vector data_elements; std::string salt; int8_t tx_power; unsigned int interval_ms; @@ -79,7 +65,8 @@ class BasePresenceRequestBuilder { : identity_(identity) {} BasePresenceRequestBuilder& SetSalt(absl::string_view salt); BasePresenceRequestBuilder& SetTxPower(int8_t tx_power); - BasePresenceRequestBuilder& SetAction(const Action& action); + BasePresenceRequestBuilder& SetActions( + std::vector data_elements); BasePresenceRequestBuilder& SetPowerMode(PowerMode power_mode); BasePresenceRequestBuilder& SetAccountName(absl::string_view account_name); BasePresenceRequestBuilder& SetManagerAppId(absl::string_view manager_app_id); @@ -87,6 +74,7 @@ class BasePresenceRequestBuilder { explicit operator BaseBroadcastRequest() const; private: + std::vector data_elements_; nearby::internal::IdentityType identity_; std::string salt_; int8_t tx_power_ = kUnspecifiedTxPower; diff --git a/presence/implementation/base_broadcast_request_test.cc b/presence/implementation/base_broadcast_request_test.cc index b27040b370..4a6c27ebce 100644 --- a/presence/implementation/base_broadcast_request_test.cc +++ b/presence/implementation/base_broadcast_request_test.cc @@ -14,15 +14,18 @@ #include "presence/implementation/base_broadcast_request.h" +#include #include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" -#include "absl/types/variant.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" #include "internal/proto/credential.pb.h" #include "presence/broadcast_request.h" #include "presence/data_element.h" +#include "presence/power_mode.h" namespace nearby { namespace presence { @@ -38,9 +41,6 @@ TEST(BroadcastRequestTest, CreateBasePresenceRequest) { BaseBroadcastRequest request = BaseBroadcastRequest( BasePresenceRequestBuilder(identity).SetTxPower(kTxPower).SetPowerMode( PowerMode::kBalanced)); - - EXPECT_TRUE(absl::holds_alternative( - request.variant)); EXPECT_EQ(request.salt.size(), 2); EXPECT_EQ(request.tx_power, kTxPower); EXPECT_EQ(request.power_mode, PowerMode::kBalanced); @@ -48,41 +48,32 @@ TEST(BroadcastRequestTest, CreateBasePresenceRequest) { TEST(BroadcastRequestTest, CreateFromPresenceRequest) { constexpr int8_t kTxPower = 30; - constexpr uint32_t kExpectedAction = - (1 << 23); // encoded kActiveUnlockAction std::string account_name = "Test account"; std::string manager_app_id = "Manager app id"; - PresenceBroadcast::BroadcastSection section = { + BroadcastRequest::BroadcastSection section = { .identity = internal::IDENTITY_TYPE_PUBLIC, .extended_properties = {DataElement( DataElement(ActionBit::kActiveUnlockAction))}, .account_name = account_name, .manager_app_id = manager_app_id}; - PresenceBroadcast presence_request = {.sections = {section}}; - BroadcastRequest input = {.tx_power = kTxPower, .variant = presence_request}; + BroadcastRequest input = { + .tx_power = kTxPower, + .sections = {section}, + }; absl::StatusOr request = BaseBroadcastRequest::Create(input); ASSERT_OK(request); EXPECT_THAT(request->tx_power, kTxPower); - EXPECT_THAT(absl::get(request->variant) - .credential_selector.identity_type, + EXPECT_THAT(request->credential_selector.identity_type, IdentityType::IDENTITY_TYPE_PUBLIC); - EXPECT_THAT(absl::get(request->variant) - .action.action, - kExpectedAction); - EXPECT_THAT(absl::get(request->variant) - .credential_selector.account_name, - account_name); - EXPECT_THAT(absl::get(request->variant) - .credential_selector.manager_app_id, - manager_app_id); + EXPECT_THAT(request->credential_selector.account_name, account_name); + EXPECT_THAT(request->credential_selector.manager_app_id, manager_app_id); } TEST(BroadcastRequestTest, CreateFromEmptyPresenceRequestFails) { BroadcastRequest empty = { - .variant = PresenceBroadcast(), }; EXPECT_THAT(BaseBroadcastRequest::Create(empty), diff --git a/presence/implementation/broadcast_manager.cc b/presence/implementation/broadcast_manager.cc index 5039db2955..eeb3af4bf7 100644 --- a/presence/implementation/broadcast_manager.cc +++ b/presence/implementation/broadcast_manager.cc @@ -32,10 +32,15 @@ #include "internal/platform/logging.h" #include "presence/broadcast_request.h" #include "presence/data_types.h" -#include "presence/implementation/advertisement_factory.h" #include "presence/implementation/base_broadcast_request.h" #include "presence/implementation/mediums/advertisement_data.h" +#ifdef USE_RUST_DECODER +#include "presence/implementation/advertisement_factory.h" +#else +#include "presence/implementation/advertisement_factory_deprecated.h" +#endif + namespace nearby { namespace presence { namespace { @@ -136,8 +141,9 @@ void BroadcastManager::FetchCredentials( credentials = std::move(*credentials), selector = std::move(selector)]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(executor_) mutable { - absl::optional credential = - Advertise(id, broadcast_request, credentials); + absl::optional // NOLINT + credential = + Advertise(id, broadcast_request, credentials); if (credential) { credential_manager_->UpdateLocalCredential( selector, std::move(*credential), @@ -193,7 +199,7 @@ absl::optional BroadcastManager::Advertise( // NOLINT NEARBY_LOGS(WARNING) << "Can't create advertisement, reason: " << advertisement.status(); NotifyStartCallbackStatus(id, advertisement.status()); - return absl::optional(); //NOLINT + return absl::optional(); // NOLINT } std::unique_ptr session = mediums_->GetBle().StartAdvertising( @@ -205,7 +211,7 @@ absl::optional BroadcastManager::Advertise( // NOLINT if (!session) { NotifyStartCallbackStatus(id, absl::InternalError("Can't start advertising")); - return absl::optional(); //NOLINT + return absl::optional(); // NOLINT } it->second.SetAdvertisingSession(std::move(session)); return credential; diff --git a/presence/implementation/broadcast_manager_test.cc b/presence/implementation/broadcast_manager_test.cc index 0e777768e3..121e7bd1cd 100644 --- a/presence/implementation/broadcast_manager_test.cc +++ b/presence/implementation/broadcast_manager_test.cc @@ -14,17 +14,24 @@ #include "presence/implementation/broadcast_manager.h" -#include +#include #include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/feature_flags.h" #include "internal/platform/future.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/single_thread_executor.h" #include "internal/proto/credential.pb.h" +#include "presence/broadcast_request.h" +#include "presence/data_element.h" +#include "presence/data_types.h" #include "presence/implementation/credential_manager_impl.h" #include "presence/implementation/mediums/mediums.h" @@ -43,17 +50,16 @@ constexpr FeatureFlags kTestCases[] = { }; constexpr absl::string_view kAccountName = "Test account"; -constexpr int8_t kTxPower = 30; +constexpr int8_t kTxPower = 19; BroadcastRequest CreateBroadcastRequest(IdentityType identity) { - PresenceBroadcast::BroadcastSection section = { + BroadcastRequest::BroadcastSection section = { .identity = identity, .extended_properties = {DataElement( DataElement(ActionBit::kActiveUnlockAction))}, .account_name = std::string(kAccountName)}; - PresenceBroadcast presence_request = {.sections = {section}}; BroadcastRequest request = {.tx_power = kTxPower, - .variant = presence_request}; + .sections = {section}}; return request; } @@ -159,7 +165,6 @@ TEST_P(BroadcastManagerTest, StartBroadcastInvalidRequestFails) { } TEST_P(BroadcastManagerTest, StartBroadcastPrivateIdentityFails) { - // TODO(b/256249404): Support private identity. absl::StatusOr session = broadcast_manager_.StartBroadcast( CreateBroadcastRequest(internal::IDENTITY_TYPE_PRIVATE_GROUP), diff --git a/presence/implementation/credential_manager_impl.cc b/presence/implementation/credential_manager_impl.cc index f957273edd..3a48c16b56 100644 --- a/presence/implementation/credential_manager_impl.cc +++ b/presence/implementation/credential_manager_impl.cc @@ -49,9 +49,7 @@ #include "internal/platform/logging.h" #include "internal/proto/credential.pb.h" #include "internal/proto/local_credential.pb.h" -#include "presence/data_types.h" #include "presence/implementation/base_broadcast_request.h" -#include "presence/implementation/ldt.h" namespace nearby { namespace presence { @@ -237,10 +235,10 @@ CredentialManagerImpl::CreateLocalCredential( private_credential.mutable_connection_signing_key()->set_key( std::string(private_key.begin(), private_key.end())); // Create an AES key to encrypt the device identity metadata. - std::string metadata_key(kBaseMetadataSize, 0); + std::string metadata_key(kV0IdentityTokenSize, 0); RandBytes(const_cast(metadata_key.data()), metadata_key.size()); - private_credential.set_metadata_encryption_key_v0(metadata_key); + private_credential.set_identity_token_v0(metadata_key); // Generate the public credential std::vector public_key; @@ -278,12 +276,12 @@ SharedCredential CredentialManagerImpl::CreatePublicCredential( std::string(public_key.begin(), public_key.end())); auto metadata_encryption_key_tag = - Crypto::Sha256(private_credential.metadata_encryption_key_v0()); - public_credential.set_metadata_encryption_key_tag_v0( + Crypto::Sha256(private_credential.identity_token_v0()); + public_credential.set_identity_token_tag_v0( std::string(metadata_encryption_key_tag.AsStringView())); auto encrypted_meta_data = EncryptDeviceIdentityMetaData( - private_credential.metadata_encryption_key_v0(), + private_credential.identity_token_v0(), private_credential.key_seed(), device_identity_metadata.SerializeAsString()); diff --git a/presence/implementation/credential_manager_impl_test.cc b/presence/implementation/credential_manager_impl_test.cc index 44d3765967..5bcb76b80c 100644 --- a/presence/implementation/credential_manager_impl_test.cc +++ b/presence/implementation/credential_manager_impl_test.cc @@ -14,6 +14,7 @@ #include "presence/implementation/credential_manager_impl.h" +#include #include #include #include @@ -36,8 +37,10 @@ #include "internal/platform/implementation/crypto.h" #include "internal/platform/logging.h" #include "internal/platform/medium_environment.h" +#include "internal/platform/single_thread_executor.h" #include "internal/proto/credential.pb.h" #include "presence/implementation/base_broadcast_request.h" +#include "presence/implementation/credential_manager.h" namespace nearby { namespace presence { @@ -243,8 +246,8 @@ TEST_F(CredentialManagerImplTest, CreateOneCredentialSuccessfully) { EXPECT_EQ(private_credential.key_seed().size(), CredentialManagerImpl::kAuthenticityKeyByteSize); EXPECT_FALSE(private_credential.connection_signing_key().key().empty()); - EXPECT_EQ(private_credential.metadata_encryption_key_v0().size(), - kBaseMetadataSize); + EXPECT_EQ(private_credential.identity_token_v0().size(), + kV0IdentityTokenSize); SharedCredential public_credential = credentials.second; // Verify the public credential. @@ -259,15 +262,15 @@ TEST_F(CredentialManagerImplTest, CreateOneCredentialSuccessfully) { EXPECT_GE(public_credential.end_time_millis(), absl::ToUnixMillis(kEndTime)); EXPECT_LE(public_credential.end_time_millis(), absl::ToUnixMillis(kEndTime + absl::Hours(3))); - EXPECT_EQ(Crypto::Sha256(private_credential.metadata_encryption_key_v0()) + EXPECT_EQ(Crypto::Sha256(private_credential.identity_token_v0()) .AsStringView(), - public_credential.metadata_encryption_key_tag_v0()); + public_credential.identity_token_tag_v0()); EXPECT_FALSE( public_credential.connection_signature_verification_key().empty()); EXPECT_FALSE(public_credential.encrypted_metadata_bytes_v0().empty()); auto decrypted_metadata = credential_manager_.DecryptDeviceIdentityMetaData( - private_credential.metadata_encryption_key_v0(), + private_credential.identity_token_v0(), public_credential.key_seed(), public_credential.encrypted_metadata_bytes_v0()); diff --git a/presence/implementation/scan_manager_test.cc b/presence/implementation/scan_manager_test.cc index c06bf3ab14..315aafdb7c 100644 --- a/presence/implementation/scan_manager_test.cc +++ b/presence/implementation/scan_manager_test.cc @@ -331,7 +331,7 @@ internal::SharedCredential GetPublicCredential() { 0xB8, 0xEA, 0x67, 0xD1, 0x1C, 0x3E, 0x36, 0xFD}); internal::SharedCredential public_credential; public_credential.set_key_seed(seed.AsStringView()); - public_credential.set_metadata_encryption_key_tag_v0( + public_credential.set_identity_token_tag_v0( known_mac.AsStringView()); return public_credential; } diff --git a/presence/presence_action.cc b/presence/presence_action.cc index 1265eadac5..019c6c4c8e 100644 --- a/presence/presence_action.cc +++ b/presence/presence_action.cc @@ -13,7 +13,6 @@ // limitations under the License. #include "presence/presence_action.h" - #include "internal/platform/logging.h" namespace nearby {