mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Update connection authenticator to account for multi-identity support.
PiperOrigin-RevId: 547880233
This commit is contained in:
committed by
Copybara-Service
parent
66d101926a
commit
770f59b748
@@ -96,7 +96,6 @@ cc_library(
|
||||
"//internal/proto:metadata_cc_proto",
|
||||
"//presence:types",
|
||||
"//presence/implementation/mediums",
|
||||
"//presence/proto:presence_frame_cc_proto",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/container:flat_hash_set",
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
|
||||
#include "presence/implementation/connection_authenticator.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
@@ -26,7 +28,6 @@
|
||||
#include "internal/crypto/secure_util.h"
|
||||
#include "internal/proto/credential.pb.h"
|
||||
#include "internal/proto/local_credential.pb.h"
|
||||
#include "presence/proto/presence_frame.pb.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace presence {
|
||||
@@ -45,70 +46,62 @@ constexpr char kDiscovererHkdfInfo[] =
|
||||
"Nearby Presence Discoverer Credential Hash";
|
||||
} // namespace
|
||||
|
||||
absl::StatusOr<std::string> ConnectionAuthenticator::BuildSignedMessage(
|
||||
absl::StatusOr<ConnectionAuthenticator::InitiatorData>
|
||||
ConnectionAuthenticator::BuildSignedMessageAsInitiator(
|
||||
absl::string_view ukey2_secret,
|
||||
const internal::LocalCredential& local_credential,
|
||||
bool is_initiator) const {
|
||||
std::optional<const internal::LocalCredential> local_credential,
|
||||
const internal::SharedCredential& shared_credential) const {
|
||||
auto shared_credential_hash = crypto::HkdfSha256(
|
||||
absl::StrCat(ukey2_secret, shared_credential.key_seed()), kHkdfSalt,
|
||||
kDiscovererHkdfInfo, kPresenceAuthenticatorHkdfKeySize);
|
||||
if (local_credential.has_value()) {
|
||||
// two-way authentication, private identity.
|
||||
auto signer = crypto::Ed25519Signer::Create(
|
||||
(*local_credential).connection_signing_key().key());
|
||||
if (!signer.ok()) {
|
||||
return signer.status();
|
||||
}
|
||||
auto pkey_signature =
|
||||
signer->Sign(absl::StrCat(kDiscovererMessageHeader, ukey2_secret));
|
||||
if (!pkey_signature.has_value()) {
|
||||
return absl::InternalError("Signing using private key failed.");
|
||||
}
|
||||
return ConnectionAuthenticator::TwoWayInitiatorData{
|
||||
.shared_credential_hash = shared_credential_hash,
|
||||
.private_key_signature = *pkey_signature,
|
||||
};
|
||||
}
|
||||
// one-way authentication, trusted identity.
|
||||
return ConnectionAuthenticator::OneWayInitiatorData{
|
||||
.shared_credential_hash = shared_credential_hash,
|
||||
};
|
||||
}
|
||||
|
||||
absl::StatusOr<ConnectionAuthenticator::ResponderData>
|
||||
ConnectionAuthenticator::BuildSignedMessageAsResponder(
|
||||
absl::string_view ukey2_secret,
|
||||
const internal::LocalCredential& local_credential) const {
|
||||
auto signer = crypto::Ed25519Signer::Create(
|
||||
local_credential.connection_signing_key().key());
|
||||
if (!signer.ok()) {
|
||||
return signer.status();
|
||||
}
|
||||
auto pkey_signature = signer->Sign(absl::StrCat(
|
||||
is_initiator ? kDiscovererMessageHeader : kBroadcasterMessageHeader,
|
||||
ukey2_secret));
|
||||
auto pkey_signature =
|
||||
signer->Sign(absl::StrCat(kBroadcasterMessageHeader, ukey2_secret));
|
||||
if (!pkey_signature.has_value()) {
|
||||
return absl::InternalError("Signing using private key failed.");
|
||||
}
|
||||
auto credential_id_hash = crypto::HkdfSha256(
|
||||
absl::StrCat(ukey2_secret, local_credential.key_seed()), kHkdfSalt,
|
||||
is_initiator ? kDiscovererHkdfInfo : kBroadcasterHkdfInfo,
|
||||
kPresenceAuthenticatorHkdfKeySize);
|
||||
PresenceFrame frame;
|
||||
frame.mutable_v1_frame()->mutable_authentication_frame()->set_version(
|
||||
kPresenceAuthenticatorVersion);
|
||||
frame.mutable_v1_frame()
|
||||
->mutable_authentication_frame()
|
||||
->set_private_key_signature(*pkey_signature);
|
||||
frame.mutable_v1_frame()
|
||||
->mutable_authentication_frame()
|
||||
->set_credential_id_hash(credential_id_hash);
|
||||
return frame.SerializeAsString();
|
||||
return ConnectionAuthenticator::ResponderData{.private_key_signature =
|
||||
*pkey_signature};
|
||||
}
|
||||
|
||||
absl::Status ConnectionAuthenticator::VerifyMessage(
|
||||
absl::string_view ukey2_secret, absl::string_view received_frame,
|
||||
const std::vector<internal::SharedCredential>& shared_credentials,
|
||||
bool is_initiator) const {
|
||||
PresenceFrame frame;
|
||||
frame.ParseFromString(std::string(received_frame));
|
||||
if (!frame.has_v1_frame() || !frame.v1_frame().has_authentication_frame()) {
|
||||
return absl::InvalidArgumentError("No presence authentication frame.");
|
||||
absl::Status ConnectionAuthenticator::VerifyMessageAsInitiator(
|
||||
ResponderData authentication_data, absl::string_view ukey2_secret,
|
||||
const std::vector<internal::SharedCredential>& shared_credentials) const {
|
||||
if (authentication_data.private_key_signature.empty()) {
|
||||
return absl::InvalidArgumentError("Empty private key signature.");
|
||||
}
|
||||
// Now we know we have an AuthenticationFrame
|
||||
PresenceAuthenticationFrame auth_frame =
|
||||
frame.v1_frame().authentication_frame();
|
||||
if (auth_frame.version() != kPresenceAuthenticatorVersion) {
|
||||
return absl::InvalidArgumentError("Presence frame has wrong version.");
|
||||
}
|
||||
if (!auth_frame.has_credential_id_hash() ||
|
||||
(auth_frame.credential_id_hash().size() !=
|
||||
kPresenceAuthenticatorHkdfKeySize)) {
|
||||
return absl::InvalidArgumentError(
|
||||
"Presence frame missing/has bad cid hash");
|
||||
}
|
||||
// We want to check each shared credential to verify using its public key.
|
||||
for (const auto& shared_credential : shared_credentials) {
|
||||
// Verify Credential ID hash.
|
||||
auto cid_hash = crypto::HkdfSha256(
|
||||
absl::StrCat(ukey2_secret, shared_credential.key_seed()), kHkdfSalt,
|
||||
is_initiator ? kBroadcasterHkdfInfo : kDiscovererHkdfInfo,
|
||||
kPresenceAuthenticatorHkdfKeySize);
|
||||
if (!crypto::SecureMemEqual(cid_hash.c_str(),
|
||||
auth_frame.credential_id_hash().c_str(),
|
||||
kPresenceAuthenticatorHkdfKeySize)) {
|
||||
continue;
|
||||
}
|
||||
auto verifier = crypto::Ed25519Verifier::Create(
|
||||
shared_credential.connection_signature_verification_key());
|
||||
if (!verifier.ok()) {
|
||||
@@ -116,15 +109,88 @@ absl::Status ConnectionAuthenticator::VerifyMessage(
|
||||
}
|
||||
// Verify ED25519 signature, returning true if verification succeeded.
|
||||
if (verifier
|
||||
->Verify(absl::StrCat(is_initiator ? kBroadcasterMessageHeader
|
||||
: kDiscovererMessageHeader,
|
||||
ukey2_secret),
|
||||
auth_frame.private_key_signature())
|
||||
->Verify(absl::StrCat(kBroadcasterMessageHeader, ukey2_secret),
|
||||
authentication_data.private_key_signature)
|
||||
.ok()) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
}
|
||||
return absl::InternalError("Unable to verify presence auth message");
|
||||
return absl::InternalError("Unable to verify responder's private key sig.");
|
||||
}
|
||||
|
||||
absl::StatusOr<internal::LocalCredential>
|
||||
ConnectionAuthenticator::VerifyMessageAsResponder(
|
||||
absl::string_view ukey2_secret, InitiatorData initiator_data,
|
||||
const std::vector<internal::LocalCredential>& local_credentials,
|
||||
const std::vector<internal::SharedCredential>& shared_credentials) const {
|
||||
std::string shared_credential_hash;
|
||||
std::optional<internal::LocalCredential> matched_local_credential;
|
||||
if (std::holds_alternative<OneWayInitiatorData>(initiator_data)) {
|
||||
// one-way. we only need to verify if the hash matches one of our
|
||||
// local credentials.
|
||||
auto auth_data = std::get<OneWayInitiatorData>(initiator_data);
|
||||
if (auth_data.shared_credential_hash.size() !=
|
||||
kPresenceAuthenticatorHkdfKeySize) {
|
||||
return absl::InvalidArgumentError("Invalid shared credential hash size.");
|
||||
}
|
||||
for (const auto& local_credential : local_credentials) {
|
||||
// Verify Credential ID hash.
|
||||
auto cid_hash = crypto::HkdfSha256(
|
||||
absl::StrCat(ukey2_secret, local_credential.key_seed()), kHkdfSalt,
|
||||
kDiscovererHkdfInfo, kPresenceAuthenticatorHkdfKeySize);
|
||||
if (crypto::SecureMemEqual(cid_hash.c_str(),
|
||||
auth_data.shared_credential_hash.c_str(),
|
||||
kPresenceAuthenticatorHkdfKeySize)) {
|
||||
matched_local_credential = local_credential;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// two-way. we need to verify if the hash matches one of our local
|
||||
// credentials _and_ make sure it matches one of our shared credentials.
|
||||
// We want to check each shared credential to verify using its public key.
|
||||
|
||||
// Match the local credential.
|
||||
auto auth_data = std::get<TwoWayInitiatorData>(initiator_data);
|
||||
if (auth_data.shared_credential_hash.size() !=
|
||||
kPresenceAuthenticatorHkdfKeySize) {
|
||||
return absl::InvalidArgumentError("Invalid shared credential hash size.");
|
||||
}
|
||||
if (auth_data.private_key_signature.empty()) {
|
||||
return absl::InvalidArgumentError("Empty private key signature.");
|
||||
}
|
||||
for (const auto& local_credential : local_credentials) {
|
||||
// Verify Credential ID hash.
|
||||
auto cid_hash = crypto::HkdfSha256(
|
||||
absl::StrCat(ukey2_secret, local_credential.key_seed()), kHkdfSalt,
|
||||
kDiscovererHkdfInfo, kPresenceAuthenticatorHkdfKeySize);
|
||||
if (crypto::SecureMemEqual(cid_hash.c_str(),
|
||||
auth_data.shared_credential_hash.c_str(),
|
||||
kPresenceAuthenticatorHkdfKeySize)) {
|
||||
matched_local_credential = local_credential;
|
||||
}
|
||||
}
|
||||
// Now, match our shared credential.
|
||||
std::optional<internal::SharedCredential> matched_shared_credential;
|
||||
for (const auto& shared_credential : shared_credentials) {
|
||||
auto verifier = crypto::Ed25519Verifier::Create(
|
||||
shared_credential.connection_signature_verification_key());
|
||||
if (!verifier.ok() ||
|
||||
verifier
|
||||
->Verify(absl::StrCat(kDiscovererMessageHeader, ukey2_secret),
|
||||
auth_data.private_key_signature)
|
||||
.ok()) {
|
||||
matched_shared_credential = shared_credential;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched_shared_credential.has_value()) {
|
||||
return absl::InternalError("Unable to verify shared credential.");
|
||||
}
|
||||
}
|
||||
if (matched_local_credential.has_value()) {
|
||||
return *matched_local_credential;
|
||||
}
|
||||
return absl::InternalError("Unable to verify local credential.");
|
||||
}
|
||||
|
||||
} // namespace presence
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_H_
|
||||
#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_H_
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -29,29 +30,67 @@ namespace presence {
|
||||
|
||||
class ConnectionAuthenticator {
|
||||
public:
|
||||
struct OneWayInitiatorData {
|
||||
std::string shared_credential_hash;
|
||||
};
|
||||
|
||||
struct TwoWayInitiatorData {
|
||||
std::string shared_credential_hash;
|
||||
std::string private_key_signature;
|
||||
};
|
||||
|
||||
struct ResponderData {
|
||||
std::string private_key_signature;
|
||||
};
|
||||
|
||||
using InitiatorData = absl::variant<OneWayInitiatorData, TwoWayInitiatorData>;
|
||||
|
||||
// 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.
|
||||
// is_initiator - True if the current client is the initiator of the current
|
||||
// connection (initiates RequestConnection()).
|
||||
absl::StatusOr<std::string> BuildSignedMessage(
|
||||
// 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<InitiatorData> BuildSignedMessageAsInitiator(
|
||||
absl::string_view ukey2_secret,
|
||||
const internal::LocalCredential& local_credential,
|
||||
bool is_initiator) const;
|
||||
std::optional<const internal::LocalCredential> local_credential,
|
||||
const internal::SharedCredential& shared_credential) const;
|
||||
|
||||
// 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<ResponderData> BuildSignedMessageAsResponder(
|
||||
absl::string_view ukey2_secret,
|
||||
const internal::LocalCredential& local_credential) const;
|
||||
|
||||
// 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<internal::SharedCredential>& shared_credentials) const;
|
||||
|
||||
// Verifies a signed message received from the Nearby Connections peer.
|
||||
// Returns absl::OkStatus() 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.
|
||||
// is_initiator - True if the current client is the initiator of the current
|
||||
// connection (initiates RequestConnection()).
|
||||
absl::Status VerifyMessage(
|
||||
absl::string_view ukey2_secret, absl::string_view received_frame,
|
||||
const std::vector<internal::SharedCredential>& shared_credentials,
|
||||
bool is_initiator) const;
|
||||
absl::StatusOr<internal::LocalCredential> VerifyMessageAsResponder(
|
||||
absl::string_view ukey2_secret, InitiatorData initiator_data,
|
||||
const std::vector<internal::LocalCredential>& local_credentials,
|
||||
const std::vector<internal::SharedCredential>& shared_credentials) const;
|
||||
};
|
||||
|
||||
} // namespace presence
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
#include "internal/crypto/ed25519.h"
|
||||
#include "internal/proto/credential.pb.h"
|
||||
#include "internal/proto/local_credential.pb.h"
|
||||
#include "presence/proto/presence_frame.pb.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace presence {
|
||||
namespace {
|
||||
|
||||
using ::protobuf_matchers::EqualsProto;
|
||||
using ::testing::status::StatusIs;
|
||||
|
||||
constexpr char kUkey2Secret[] = {0x34, 0x56, 0x78, 0x90};
|
||||
@@ -53,257 +53,220 @@ internal::SharedCredential BuildSharedCredential(
|
||||
return shared_credential;
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestSignHasV1AuthFrame) {
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
std::string auth_msg;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), true));
|
||||
PresenceFrame frame;
|
||||
frame.ParseFromString(auth_msg);
|
||||
EXPECT_TRUE(frame.has_v1_frame());
|
||||
EXPECT_TRUE(frame.v1_frame().has_authentication_frame());
|
||||
}
|
||||
class PresenceAuthenticatorTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
ASSERT_OK_AND_ASSIGN(auto key_pair1, key_pair_or_status);
|
||||
auto key_pair2_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
ASSERT_OK_AND_ASSIGN(auto key_pair2, key_pair2_or_status);
|
||||
initiator_local_credential_ = BuildLocalCredential(key_pair1, kKeySeed1);
|
||||
initiator_shared_credential_ = BuildSharedCredential(key_pair1, kKeySeed1);
|
||||
initiator_shared_credential_wrong_key_ =
|
||||
BuildSharedCredential(key_pair2, kKeySeed1);
|
||||
responder_local_credential_ = BuildLocalCredential(key_pair2, kKeySeed2);
|
||||
responder_shared_credential_ = BuildSharedCredential(key_pair2, kKeySeed2);
|
||||
responder_shared_credential_wrong_key_ =
|
||||
BuildSharedCredential(key_pair1, kKeySeed2);
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestInitiatorSignResponderVerify) {
|
||||
internal::LocalCredential initiator_local_credential_;
|
||||
internal::LocalCredential responder_local_credential_;
|
||||
internal::SharedCredential initiator_shared_credential_;
|
||||
internal::SharedCredential initiator_shared_credential_wrong_key_;
|
||||
internal::SharedCredential responder_shared_credential_;
|
||||
internal::SharedCredential responder_shared_credential_wrong_key_;
|
||||
};
|
||||
|
||||
TEST_F(PresenceAuthenticatorTest, TestTwoWayInitiatorSignResponderVerify) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
std::string auth_msg;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
initiator_authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), true));
|
||||
EXPECT_OK(responder_authenticator.VerifyMessage(
|
||||
kUkey2Secret, auth_msg, {BuildSharedCredential(key_pair, kKeySeed1)},
|
||||
false));
|
||||
ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data,
|
||||
initiator_authenticator.BuildSignedMessageAsInitiator(
|
||||
kUkey2Secret, initiator_local_credential_,
|
||||
responder_shared_credential_));
|
||||
auto local_credential = responder_authenticator.VerifyMessageAsResponder(
|
||||
kUkey2Secret, auth_data, {responder_local_credential_},
|
||||
{initiator_shared_credential_});
|
||||
ASSERT_TRUE(local_credential.ok());
|
||||
EXPECT_THAT(*local_credential, EqualsProto(responder_local_credential_));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestResponderSignInitiatorVerify) {
|
||||
TEST_F(PresenceAuthenticatorTest, TestOneWayInitiatorSignResponderVerify) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
std::string auth_msg,
|
||||
responder_authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), false));
|
||||
EXPECT_OK(initiator_authenticator.VerifyMessage(
|
||||
kUkey2Secret, auth_msg, {BuildSharedCredential(key_pair, kKeySeed1)},
|
||||
true));
|
||||
ConnectionAuthenticator::InitiatorData auth_data,
|
||||
initiator_authenticator.BuildSignedMessageAsInitiator(
|
||||
kUkey2Secret, std::nullopt, responder_shared_credential_));
|
||||
auto local_credential = responder_authenticator.VerifyMessageAsResponder(
|
||||
kUkey2Secret, auth_data, {responder_local_credential_},
|
||||
{initiator_shared_credential_});
|
||||
ASSERT_TRUE(local_credential.ok());
|
||||
EXPECT_THAT(*local_credential, EqualsProto(responder_local_credential_));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestInitiatorSignInitiatorVerifyFails) {
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
std::string auth_msg;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
initiator_authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), true));
|
||||
EXPECT_THAT(initiator_authenticator.VerifyMessage(
|
||||
kUkey2Secret, auth_msg,
|
||||
{BuildSharedCredential(key_pair, kKeySeed1)}, true),
|
||||
StatusIs(absl::StatusCode::kInternal));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestResponderSignResponderVerifyFails) {
|
||||
TEST_F(PresenceAuthenticatorTest, TestResponderSignInitiatorVerify) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
std::string auth_msg;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
responder_authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), false));
|
||||
EXPECT_THAT(responder_authenticator.VerifyMessage(
|
||||
kUkey2Secret, auth_msg,
|
||||
{BuildSharedCredential(key_pair, kKeySeed1)}, false),
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data,
|
||||
responder_authenticator.BuildSignedMessageAsResponder(
|
||||
kUkey2Secret, responder_local_credential_));
|
||||
EXPECT_OK(initiator_authenticator.VerifyMessageAsInitiator(
|
||||
auth_data, kUkey2Secret, {responder_shared_credential_}));
|
||||
}
|
||||
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestTwoWayInitiatorSignResponderVerifyNoSharedCredentialMatchFails) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data,
|
||||
initiator_authenticator.BuildSignedMessageAsInitiator(
|
||||
kUkey2Secret, initiator_local_credential_,
|
||||
responder_shared_credential_));
|
||||
EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder(
|
||||
kUkey2Secret, auth_data, {}, {initiator_shared_credential_}),
|
||||
StatusIs(absl::StatusCode::kInternal));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestBadKeypairSignVerifyFails) {
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
auto key_pair_or_status2 = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair2;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair2, key_pair_or_status2);
|
||||
std::string auth_msg;
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestOneWayInitiatorSignResponderVerifyNoMatchCredentialFails) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), true));
|
||||
EXPECT_THAT(authenticator.VerifyMessage(
|
||||
kUkey2Secret, auth_msg,
|
||||
{BuildSharedCredential(key_pair2, kKeySeed1)}, false),
|
||||
ConnectionAuthenticator::InitiatorData auth_data,
|
||||
initiator_authenticator.BuildSignedMessageAsInitiator(
|
||||
kUkey2Secret, std::nullopt, responder_shared_credential_));
|
||||
EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder(
|
||||
kUkey2Secret, auth_data, {}, {initiator_shared_credential_}),
|
||||
StatusIs(absl::StatusCode::kInternal));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestBadKeyseedSignVerifyFails) {
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
std::string auth_msg;
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestOneWayInitiatorSignResponderVerifyNoCredentialFails) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), true));
|
||||
EXPECT_THAT(authenticator.VerifyMessage(
|
||||
kUkey2Secret, auth_msg,
|
||||
{BuildSharedCredential(key_pair, kKeySeed2)}, false),
|
||||
ConnectionAuthenticator::InitiatorData auth_data,
|
||||
initiator_authenticator.BuildSignedMessageAsInitiator(
|
||||
kUkey2Secret, std::nullopt, responder_shared_credential_));
|
||||
EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder(
|
||||
kUkey2Secret, auth_data, {}, {}),
|
||||
StatusIs(absl::StatusCode::kInternal));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestBadSharedCredentialSignVerifyFails) {
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
auto key_pair_or_status2 = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair2;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair2, key_pair_or_status2);
|
||||
std::string auth_msg;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), true));
|
||||
EXPECT_THAT(authenticator.VerifyMessage(
|
||||
kUkey2Secret, auth_msg,
|
||||
{BuildSharedCredential(key_pair2, kKeySeed2)}, false),
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestTwoWayInitiatorSignResponderVerifyNoMatchCredentialFails) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data,
|
||||
initiator_authenticator.BuildSignedMessageAsInitiator(
|
||||
kUkey2Secret, initiator_local_credential_,
|
||||
responder_shared_credential_));
|
||||
EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder(
|
||||
kUkey2Secret, auth_data, {}, {initiator_shared_credential_}),
|
||||
StatusIs(absl::StatusCode::kInternal));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestBadPresenceFrameFails) {
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
std::string auth_msg = "\x34\x45";
|
||||
EXPECT_THAT(authenticator.VerifyMessage(
|
||||
kUkey2Secret, auth_msg,
|
||||
{BuildSharedCredential(key_pair, kKeySeed1)}, false),
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestTwoWayInitiatorSignResponderVerifyWrongKeyFails) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data,
|
||||
initiator_authenticator.BuildSignedMessageAsInitiator(
|
||||
kUkey2Secret, initiator_local_credential_,
|
||||
responder_shared_credential_));
|
||||
EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder(
|
||||
kUkey2Secret, auth_data, {responder_local_credential_},
|
||||
{initiator_shared_credential_wrong_key_}),
|
||||
StatusIs(absl::StatusCode::kInternal));
|
||||
}
|
||||
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestResponderSignInitiatorVerifyNoMatchCredentialFails) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data,
|
||||
responder_authenticator.BuildSignedMessageAsResponder(
|
||||
kUkey2Secret, responder_local_credential_));
|
||||
EXPECT_THAT(initiator_authenticator.VerifyMessageAsInitiator(
|
||||
auth_data, kUkey2Secret, {}),
|
||||
StatusIs(absl::StatusCode::kInternal));
|
||||
}
|
||||
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestResponderSignInitiatorVerifyWrongKeyFails) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data,
|
||||
responder_authenticator.BuildSignedMessageAsResponder(
|
||||
kUkey2Secret, responder_local_credential_));
|
||||
EXPECT_THAT(
|
||||
initiator_authenticator.VerifyMessageAsInitiator(
|
||||
auth_data, kUkey2Secret, {responder_shared_credential_wrong_key_}),
|
||||
StatusIs(absl::StatusCode::kInternal));
|
||||
}
|
||||
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestTwoWayInitiatorSignResponderVerifyNoCidHashFails) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data,
|
||||
initiator_authenticator.BuildSignedMessageAsInitiator(
|
||||
kUkey2Secret, initiator_local_credential_,
|
||||
responder_shared_credential_));
|
||||
std::get<ConnectionAuthenticator::TwoWayInitiatorData>(auth_data)
|
||||
.shared_credential_hash.clear();
|
||||
EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder(
|
||||
kUkey2Secret, auth_data, {responder_local_credential_},
|
||||
{initiator_shared_credential_wrong_key_}),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestNoV1FrameFails) {
|
||||
PresenceFrame frame;
|
||||
ASSERT_FALSE(frame.has_v1_frame());
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
EXPECT_THAT(authenticator.VerifyMessage(
|
||||
kUkey2Secret, frame.SerializeAsString(),
|
||||
{BuildSharedCredential(key_pair, kKeySeed1)}, false),
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestTwoWayInitiatorSignResponderVerifyNoPkeySigFails) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data,
|
||||
initiator_authenticator.BuildSignedMessageAsInitiator(
|
||||
kUkey2Secret, initiator_local_credential_,
|
||||
responder_shared_credential_));
|
||||
std::get<ConnectionAuthenticator::TwoWayInitiatorData>(auth_data)
|
||||
.private_key_signature.clear();
|
||||
EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder(
|
||||
kUkey2Secret, auth_data, {responder_local_credential_},
|
||||
{initiator_shared_credential_wrong_key_}),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestNoAuthFrameFails) {
|
||||
PresenceFrame frame;
|
||||
frame.mutable_v1_frame()->clear_authentication_frame();
|
||||
ASSERT_TRUE(frame.has_v1_frame());
|
||||
ASSERT_FALSE(frame.v1_frame().has_authentication_frame());
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
EXPECT_THAT(authenticator.VerifyMessage(
|
||||
kUkey2Secret, frame.SerializeAsString(),
|
||||
{BuildSharedCredential(key_pair, kKeySeed1)}, false),
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestOneWayInitiatorSignResponderVerifyNoCidHashFails) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
ConnectionAuthenticator::InitiatorData auth_data,
|
||||
initiator_authenticator.BuildSignedMessageAsInitiator(
|
||||
kUkey2Secret, std::nullopt, responder_shared_credential_));
|
||||
std::get<ConnectionAuthenticator::OneWayInitiatorData>(auth_data)
|
||||
.shared_credential_hash.clear();
|
||||
EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder(
|
||||
kUkey2Secret, auth_data, {responder_local_credential_},
|
||||
{initiator_shared_credential_}),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestBadVersionFails) {
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
std::string auth_msg;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), true));
|
||||
PresenceFrame frame;
|
||||
frame.ParseFromString(auth_msg);
|
||||
frame.mutable_v1_frame()->mutable_authentication_frame()->set_version(2);
|
||||
EXPECT_THAT(authenticator.VerifyMessage(
|
||||
kUkey2Secret, frame.SerializeAsString(),
|
||||
{BuildSharedCredential(key_pair, kKeySeed1)}, false),
|
||||
TEST_F(PresenceAuthenticatorTest,
|
||||
TestResponderSignInitiatorVerifyNoPkeySigFail) {
|
||||
ConnectionAuthenticator responder_authenticator;
|
||||
ConnectionAuthenticator initiator_authenticator;
|
||||
ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data,
|
||||
responder_authenticator.BuildSignedMessageAsResponder(
|
||||
kUkey2Secret, responder_local_credential_));
|
||||
auth_data.private_key_signature.clear();
|
||||
EXPECT_THAT(initiator_authenticator.VerifyMessageAsInitiator(
|
||||
auth_data, kUkey2Secret, {responder_shared_credential_}),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestMissingCredentialIdHashFails) {
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
std::string auth_msg;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), true));
|
||||
PresenceFrame frame;
|
||||
frame.ParseFromString(auth_msg);
|
||||
frame.mutable_v1_frame()
|
||||
->mutable_authentication_frame()
|
||||
->clear_credential_id_hash();
|
||||
EXPECT_THAT(authenticator.VerifyMessage(
|
||||
kUkey2Secret, frame.SerializeAsString(),
|
||||
{BuildSharedCredential(key_pair, kKeySeed1)}, false),
|
||||
StatusIs(absl::StatusCode::kInvalidArgument));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestMissingPrivateKeySignatureFails) {
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
std::string auth_msg;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), true));
|
||||
PresenceFrame frame;
|
||||
frame.ParseFromString(auth_msg);
|
||||
frame.mutable_v1_frame()
|
||||
->mutable_authentication_frame()
|
||||
->clear_private_key_signature();
|
||||
EXPECT_THAT(authenticator.VerifyMessage(
|
||||
kUkey2Secret, frame.SerializeAsString(),
|
||||
{BuildSharedCredential(key_pair, kKeySeed1)}, false),
|
||||
StatusIs(absl::StatusCode::kInternal));
|
||||
}
|
||||
|
||||
TEST(PresenceAuthenticatorTest, TestMissingPublicKeyVerifyFails) {
|
||||
ConnectionAuthenticator authenticator;
|
||||
auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair();
|
||||
crypto::Ed25519KeyPair key_pair;
|
||||
ASSERT_OK_AND_ASSIGN(key_pair, key_pair_or_status);
|
||||
std::string auth_msg;
|
||||
ASSERT_OK_AND_ASSIGN(
|
||||
auth_msg,
|
||||
authenticator.BuildSignedMessage(
|
||||
kUkey2Secret, BuildLocalCredential(key_pair, kKeySeed1), true));
|
||||
key_pair.public_key.clear();
|
||||
EXPECT_THAT(authenticator.VerifyMessage(
|
||||
kUkey2Secret, auth_msg,
|
||||
{BuildSharedCredential(key_pair, kKeySeed1)}, true),
|
||||
StatusIs(absl::StatusCode::kInternal));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace presence
|
||||
} // namespace nearby
|
||||
|
||||
Reference in New Issue
Block a user