constexpr int64_t KEY_GA_RSP_EP_ATT = 0x09;
constexpr int64_t KEY_GA_RSP_ATT_STMT = 0x0A;
+// Update message
+constexpr int64_t KEY_UP_LINK_INFO = 0x01;
+constexpr int64_t KEY_UP_CMD_CONTACT_ID = 0x01;
+constexpr int64_t KEY_UP_CMD_LINK_ID = 0x02;
+constexpr int64_t KEY_UP_CMD_LINK_SECRET = 0x03;
+constexpr int64_t KEY_UP_CMD_AUTHENTICATOR_PUBLIC_KEY = 0x04;
+constexpr int64_t KEY_UP_CMD_AUTHENTICATOR_NAME = 0x05;
+constexpr int64_t KEY_UP_CMD_HANDSHAKE_SIGNATURE = 0x06;
+
void SerializePubkeyCredDescriptors(CborEncoding::SortedMap &map,
const CborEncoding::Key &key,
const wauthn_pubkey_cred_descriptors_s &credentials)
m_longTouchForReset = getInfoMap.GetBooleanAt(KEY_GI_RSP_LONG_TOUCH_FOR_RESET);
}
+void UpdateMessage::Deserialize(BufferView &input)
+{
+
+ auto helper = CborParsing::Parser::Create(input.data(), input.size());
+ auto map = helper.EnterMap();
+
+ auto linkingMap = map.EnterMapAt(KEY_UP_LINK_INFO);
+ if (!linkingMap)
+ return;
+
+ m_linkData = {linkingMap->GetByteStringAt(KEY_UP_CMD_CONTACT_ID).value(),
+ linkingMap->GetByteStringAt(KEY_UP_CMD_LINK_ID).value(),
+ linkingMap->GetByteStringAt(KEY_UP_CMD_LINK_SECRET).value(),
+ linkingMap->GetByteStringAt(KEY_UP_CMD_AUTHENTICATOR_PUBLIC_KEY).value(),
+ linkingMap->GetTextStringAt(KEY_UP_CMD_AUTHENTICATOR_NAME).value(),
+ linkingMap->GetByteStringAt(KEY_UP_CMD_HANDSHAKE_SIGNATURE).value()};
+
+ if (m_linkData->m_linkId.size() != 8)
+ THROW_UNKNOWN("Wrong link ID length " << m_linkData->m_linkId.size());
+ if (m_linkData->m_linkSecret.size() != 32)
+ THROW_UNKNOWN("Wrong link secret length " << m_linkData->m_linkSecret.size());
+ if (m_linkData->m_authenticatorPublicKey.size() != 65)
+ THROW_UNKNOWN("Wrong authenticator public key length "
+ << m_linkData->m_authenticatorPublicKey.size());
+ if (m_linkData->m_handshakeSignature.size() != 32)
+ THROW_UNKNOWN("Wrong handshake signature length "
+ << m_linkData->m_handshakeSignature.size());
+}
+
+void UpdateMessage::Notify(IMessageObserver &observer) { observer.HandleUpdateMessage(*this); }
std::string m_userDisplayName;
};
+// Contains only CBOR map
+class UpdateMessage : public IIncomingNotifyingMessage {
+public:
+ void Deserialize(BufferView &input) override;
+ void Notify(IMessageObserver &observer) override;
+
+ struct LinkData {
+ Buffer m_contactId;
+ Buffer m_linkId;
+ Buffer m_linkSecret;
+ Buffer m_authenticatorPublicKey;
+ std::string m_authenticatorName;
+ Buffer m_handshakeSignature;
+ };
+
+ const std::optional<LinkData> &GetLinkData() const { return m_linkData; }
+
+private:
+ std::optional<LinkData> m_linkData;
+};
+
class IMessageObserver {
public:
virtual void HandleMakeCredentialResponse(const MakeCredentialResponse &response) = 0;
virtual void HandleGetAssertionResponse(const GetAssertionResponse &response) = 0;
+ virtual void HandleUpdateMessage(const UpdateMessage &response) = 0;
virtual ~IMessageObserver() = default;
};
template <typename T>
void AssertEq(const T &left, const uint8_t *rightData, size_t rightSize)
{
- ASSERT_EQ(BufferView(left.data(), left.size()), BufferView(rightData, rightSize));
+ ASSERT_EQ(BufferView(reinterpret_cast<const uint8_t *>(left.data()), left.size()),
+ BufferView(rightData, rightSize));
}
// from chromium/device/fido/fido_test_data.h
ASSERT_TRUE(msg.m_userName.empty());
ASSERT_TRUE(msg.m_userDisplayName.empty());
}
+
+TEST(Messages, ParseUpdateMessage)
+{
+ // sample value received from an Android authenticator during manual testing
+ constexpr uint8_t blob[] =
+ "\xa2\x00\x58\xaf\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x01\xa7\x01\x58\x98\x64\x2d\x51\x6b\x57\x6e\x54\x6d\x77\x53\x45\x3a\x41\x50"
+ "\x41\x39\x31\x62\x48\x76\x72\x44\x72\x39\x53\x64\x44\x31\x71\x39\x4a\x69\x4d\x55\x78\x52"
+ "\x38\x57\x30\x41\x5a\x48\x57\x61\x56\x31\x4d\x46\x4b\x36\x77\x4f\x56\x78\x70\x76\x38\x30"
+ "\x47\x37\x59\x57\x79\x5a\x51\x72\x77\x68\x6b\x6c\x66\x57\x55\x31\x4a\x6e\x6b\x6e\x59\x78"
+ "\x4e\x6d\x45\x69\x64\x33\x4f\x4e\x59\x6f\x4d\x77\x6f\x6a\x34\x56\x33\x51\x69\x33\x68\x6f"
+ "\x59\x57\x39\x6d\x31\x71\x42\x6e\x4f\x76\x55\x69\x63\x55\x57\x49\x68\x4d\x63\x56\x42\x64"
+ "\x69\x73\x39\x69\x67\x4d\x5a\x34\x79\x2d\x48\x7a\x6b\x31\x35\x65\x42\x4d\x63\x58\x39\x6e"
+ "\x63\x6a\x69\x6b\x74\x2d\x02\x48\xc3\x38\xcc\xd2\x66\x09\x9c\xff\x03\x58\x20\xcc\x2f\xaa"
+ "\xf2\x37\x92\x3e\xda\xa1\x1f\xc8\x7e\x3e\x60\xe5\x52\xf6\xa0\xe9\x67\x78\xa7\x31\xda\x1e"
+ "\xa9\xd6\x6c\x29\xd9\xa6\x5b\x04\x58\x41\x04\x4d\x7a\xcd\xb4\x1c\x63\x70\x56\x43\x37\xc3"
+ "\x7d\x20\xa3\x05\x64\x8d\x16\x6c\xa2\x41\xaa\x96\x90\xea\x9a\xde\xd2\x01\xab\x3d\x93\x08"
+ "\x13\x54\xd9\x99\x16\x18\x80\xfd\x3b\x21\x26\xf4\xbb\xdb\x43\x35\x80\xed\x3e\x2b\xe2\x43"
+ "\x5a\x31\xcf\xc6\x05\x5d\x3e\xfe\xb5\x05\x65\x4d\x69\x20\x41\x32\x06\x58\x20\x35\x5a\xbb"
+ "\xcf\x8f\x6a\xca\xaa\xda\x49\xee\x3d\xf0\xf3\xd6\x4c\x88\x35\x1b\xd6\x69\x51\x2f\x98\xe6"
+ "\xad\x8e\x80\xcf\x50\xb0\x09\x19\x03\xe7\xf5";
+ BufferView view(blob, sizeof(blob) - 1);
+
+ UpdateMessage msg;
+ ASSERT_NO_THROW(msg.Deserialize(view));
+
+ auto linkDataOpt = msg.GetLinkData();
+ ASSERT_TRUE(linkDataOpt.has_value());
+ const auto &linkData = *linkDataOpt;
+
+ AssertEq(linkData.m_contactId, blob + 184, 152);
+ AssertEq(linkData.m_linkId, blob + 338, 8);
+ AssertEq(linkData.m_linkSecret, blob + 349, 32);
+ AssertEq(linkData.m_authenticatorPublicKey, blob + 384, 65);
+ AssertEq(linkData.m_authenticatorName, blob + 451, 5);
+ AssertEq(linkData.m_handshakeSignature, blob + 459, 32);
+}