1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <algorithm>
16 #include <array>
17 #include <cstdint>
18 #include <span>
19 #include <string>
20 
21 #include "absl/status/status.h"
22 #include "gtest/gtest.h"
23 #include "nearby_protocol.h"
24 #include "np_cpp_ffi_types.h"
25 #include "np_cpp_test.h"
26 #include "shared_test_util.h"
27 
28 // NOLINTBEGIN(readability-magic-numbers)
TEST_F(NpCppTest,V0PrivateIdentityDeserializationSimpleCase)29 TEST_F(NpCppTest, V0PrivateIdentityDeserializationSimpleCase) {
30   nearby_protocol::CredentialSlab slab;
31   const std::span<uint8_t> metadata_span(V0AdvEncryptedMetadata);
32   const nearby_protocol::MatchedCredentialData match_data(123, metadata_span);
33   std::array<uint8_t, 32> key_seed = {};
34   std::fill_n(key_seed.begin(), 32, 0x11);
35   const nearby_protocol::V0MatchableCredential v0_cred(
36       key_seed, V0AdvLegacyIdentityTokenHmac, match_data);
37   slab.AddV0Credential(v0_cred);
38   nearby_protocol::CredentialBook book(slab);
39 
40   auto deserialize_result =
41       nearby_protocol::Deserializer::DeserializeAdvertisement(
42           V0AdvEncryptedPayload, book);
43   ASSERT_EQ(deserialize_result.GetKind(),
44             nearby_protocol::DeserializeAdvertisementResultKind::V0);
45 
46   auto v0_adv = deserialize_result.IntoV0();
47   auto kind = v0_adv.GetKind();
48   ASSERT_EQ(kind, nearby_protocol::DeserializedV0AdvertisementKind::Legible);
49 
50   auto legible_adv = v0_adv.IntoLegible();
51   auto identity_kind = legible_adv.GetIdentityKind();
52   ASSERT_EQ(identity_kind,
53             nearby_protocol::DeserializedV0IdentityKind::Decrypted);
54   ASSERT_EQ(legible_adv.GetNumberOfDataElements(), 1);
55 
56   auto payload = legible_adv.IntoPayload();
57   auto de = payload.TryGetDataElement(0);
58   ASSERT_TRUE(de.ok());
59 
60   auto metadata = payload.TryDecryptMetadata();
61   ASSERT_TRUE(metadata.ok());
62   ASSERT_EQ(ExpectedV0DecryptedMetadata,
63             std::string(metadata->begin(), metadata->end()));
64 
65   auto identity_details = payload.TryGetIdentityDetails();
66   ASSERT_TRUE(identity_details.ok());
67   ASSERT_EQ(identity_details->cred_id, 123u);
68 
69   auto de_type = de->GetKind();
70   ASSERT_EQ(de_type, nearby_protocol::V0DataElementKind::TxPower);
71 
72   auto tx_power_de = de->AsTxPower();
73   ASSERT_EQ(tx_power_de.GetAsI8(), 3);
74 }
75 
CreateEmptyCredBook()76 nearby_protocol::CredentialBook CreateEmptyCredBook() {
77   nearby_protocol::CredentialSlab slab;
78   nearby_protocol::CredentialBook book(slab);
79   return book;
80 }
81 
TEST_F(NpCppTest,V0PrivateIdentityEmptyBook)82 TEST_F(NpCppTest, V0PrivateIdentityEmptyBook) {
83   auto book = CreateEmptyCredBook();
84   auto deserialize_result =
85       nearby_protocol::Deserializer::DeserializeAdvertisement(
86           V0AdvEncryptedPayload, book);
87   ASSERT_EQ(deserialize_result.GetKind(),
88             nearby_protocol::DeserializeAdvertisementResultKind::V0);
89 
90   auto v0_adv = deserialize_result.IntoV0();
91   ASSERT_EQ(
92       v0_adv.GetKind(),
93       nearby_protocol::DeserializedV0AdvertisementKind::NoMatchingCredentials);
94 
95   // Should not be able to actually access contents
96   ASSERT_DEATH([[maybe_unused]] auto failure = v0_adv.IntoLegible(), "");
97 }
98 
TEST_F(NpCppTest,V0PrivateIdentityNoMatchingCreds)99 TEST_F(NpCppTest, V0PrivateIdentityNoMatchingCreds) {
100   nearby_protocol::CredentialSlab slab;
101   uint8_t metadata[] = {0};
102   const std::span<uint8_t> metadata_span(metadata);
103   const nearby_protocol::MatchedCredentialData match_data(123, metadata_span);
104   // A randomly picked key seed, does NOT match what was used for the canned adv
105   std::array<uint8_t, 32> key_seed = {};
106   std::fill_n(key_seed.begin(), 31, 0x11);
107   const nearby_protocol::V0MatchableCredential v0_cred(
108       key_seed, V0AdvLegacyIdentityTokenHmac, match_data);
109   slab.AddV0Credential(v0_cred);
110 
111   nearby_protocol::CredentialBook book(slab);
112 
113   auto deserialize_result =
114       nearby_protocol::Deserializer::DeserializeAdvertisement(
115           V0AdvEncryptedPayload, book);
116   ASSERT_EQ(deserialize_result.GetKind(),
117             nearby_protocol::DeserializeAdvertisementResultKind::V0);
118 
119   auto v0_adv = deserialize_result.IntoV0();
120   ASSERT_EQ(
121       v0_adv.GetKind(),
122       nearby_protocol::DeserializedV0AdvertisementKind::NoMatchingCredentials);
123 
124   // Should not be able to actually access contents
125   ASSERT_DEATH([[maybe_unused]] auto failure = v0_adv.IntoLegible(), "");
126 }
127 
128 // Make sure the correct credential is matched out of multiple provided
TEST_F(NpCppTest,V0PrivateIdentityMultipleCredentials)129 TEST_F(NpCppTest, V0PrivateIdentityMultipleCredentials) {
130   nearby_protocol::CredentialSlab slab;
131   const std::span<uint8_t> metadata_span(V0AdvEncryptedMetadata);
132   std::array<uint8_t, 32> key_seed = {};
133   // Non matching credential
134   const nearby_protocol::MatchedCredentialData match_data(123, metadata_span);
135   std::fill_n(key_seed.begin(), 32, 0x12);
136   const nearby_protocol::V0MatchableCredential v0_cred(
137       key_seed, V0AdvLegacyIdentityTokenHmac, match_data);
138   slab.AddV0Credential(v0_cred);
139 
140   // Matching credential
141   const nearby_protocol::MatchedCredentialData match_data2(456, metadata_span);
142   std::fill_n(key_seed.begin(), 32, 0x11);
143   const nearby_protocol::V0MatchableCredential v0_cred2(
144       key_seed, V0AdvLegacyIdentityTokenHmac, match_data2);
145   slab.AddV0Credential(v0_cred2);
146 
147   // Non matching credential
148   const nearby_protocol::MatchedCredentialData match_data3(789, metadata_span);
149   std::fill_n(key_seed.begin(), 32, 0x13);
150   const nearby_protocol::V0MatchableCredential v0_cred3(
151       key_seed, V0AdvLegacyIdentityTokenHmac, match_data3);
152   slab.AddV0Credential(v0_cred3);
153 
154   nearby_protocol::CredentialBook book(slab);
155   auto legible_adv = nearby_protocol::Deserializer::DeserializeAdvertisement(
156                          V0AdvEncryptedPayload, book)
157                          .IntoV0()
158                          .IntoLegible();
159   ASSERT_EQ(legible_adv.GetIdentityKind(),
160             nearby_protocol::DeserializedV0IdentityKind::Decrypted);
161   ASSERT_EQ(legible_adv.GetNumberOfDataElements(), 1);
162 
163   auto payload = legible_adv.IntoPayload();
164   ASSERT_TRUE(payload.TryGetDataElement(0).ok());
165 
166   // Make sure the correct credential matches
167   auto identity_details = payload.TryGetIdentityDetails();
168   ASSERT_TRUE(identity_details.ok());
169   ASSERT_EQ(identity_details->cred_id, 456u);
170 }
171 // NOLINTEND(readability-magic-numbers)
172