Update connection authenticator to account for multi-identity support.

PiperOrigin-RevId: 547880233
This commit is contained in:
Anay Wadhera
2023-07-13 12:18:05 -07:00
committed by Copybara-Service
parent 66d101926a
commit 770f59b748
4 changed files with 353 additions and 286 deletions
-1
View File
@@ -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