[WebAuthN] Import CTAP HID message and packet structure from Chromium
authorjiewen_tan@apple.com <jiewen_tan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Oct 2018 19:32:41 +0000 (19:32 +0000)
committerjiewen_tan@apple.com <jiewen_tan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Oct 2018 19:32:41 +0000 (19:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189289
<rdar://problem/44120310>

Reviewed by Brent Fulgham.

Source/WebCore:

This patch imports CTAP HID message and packet structure:
https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html#message-and-packet-structure
from Chromium. With this library, WebKit can now turn binaries into messages that CTAP devices could understand.
This patch contains the following Chromium files and modifies them to fit into WebKit:
https://cs.chromium.org/chromium/src/device/fido/fido_constants.cc?l=1&rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
https://cs.chromium.org/chromium/src/device/fido/fido_constants.h?l=1&rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
https://cs.chromium.org/chromium/src/device/fido/hid/fido_hid_message.cc?l=1&rcl=387f3725de2842e0e6b7175a9b2ed472b0cf781a
https://cs.chromium.org/chromium/src/device/fido/hid/fido_hid_message.h?rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
https://cs.chromium.org/chromium/src/device/fido/hid/fido_hid_packet.cc?rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
https://cs.chromium.org/chromium/src/device/fido/hid/fido_hid_packet.h?rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
https://cs.chromium.org/chromium/src/device/fido/hid/fido_hid_message_unittest.cc?rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75

Covered by API tests.

* Modules/webauthn/fido/FidoConstants.cpp: Added.
(fido::isFidoHidDeviceCommand):
* Modules/webauthn/fido/FidoConstants.h: Added.
* Modules/webauthn/fido/FidoHidMessage.cpp: Added.
(fido::FidoHidMessage::create):
(fido::FidoHidMessage::createFromSerializedData):
(fido::FidoHidMessage::messageComplete const):
(fido::FidoHidMessage::getMessagePayload const):
(fido::FidoHidMessage::popNextPacket):
(fido::FidoHidMessage::addContinuationPacket):
(fido::FidoHidMessage::numPackets const):
(fido::FidoHidMessage::FidoHidMessage):
* Modules/webauthn/fido/FidoHidMessage.h: Added.
* Modules/webauthn/fido/FidoHidPacket.cpp: Added.
(fido::FidoHidPacket::FidoHidPacket):
(fido::FidoHidInitPacket::createFromSerializedData):
(fido::FidoHidInitPacket::FidoHidInitPacket):
(fido::FidoHidInitPacket::getSerializedData const):
(fido::FidoHidContinuationPacket::createFromSerializedData):
(fido::FidoHidContinuationPacket::FidoHidContinuationPacket):
(fido::FidoHidContinuationPacket::getSerializedData const):
* Modules/webauthn/fido/FidoHidPacket.h: Added.
* Modules/webauthn/fido/FidoParsingUtils.cpp: Added.
(fido::getInitPacketData):
(fido::getContinuationPacketData):
* Modules/webauthn/fido/FidoParsingUtils.h: Added.
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:

Tools:

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebCore/FidoHidMessageTest.cpp: Added.
(TestWebKitAPI::TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236976 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Modules/webauthn/fido/FidoConstants.cpp [new file with mode: 0644]
Source/WebCore/Modules/webauthn/fido/FidoConstants.h [new file with mode: 0644]
Source/WebCore/Modules/webauthn/fido/FidoHidMessage.cpp [new file with mode: 0644]
Source/WebCore/Modules/webauthn/fido/FidoHidMessage.h [new file with mode: 0644]
Source/WebCore/Modules/webauthn/fido/FidoHidPacket.cpp [new file with mode: 0644]
Source/WebCore/Modules/webauthn/fido/FidoHidPacket.h [new file with mode: 0644]
Source/WebCore/Modules/webauthn/fido/FidoParsingUtils.cpp [new file with mode: 0644]
Source/WebCore/Modules/webauthn/fido/FidoParsingUtils.h [new file with mode: 0644]
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebCore/FidoHidMessageTest.cpp [new file with mode: 0644]

index bff2fe3..64fb8d1 100644 (file)
@@ -1,3 +1,54 @@
+2018-10-09  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthN] Import CTAP HID message and packet structure from Chromium
+        https://bugs.webkit.org/show_bug.cgi?id=189289
+        <rdar://problem/44120310>
+
+        Reviewed by Brent Fulgham.
+
+        This patch imports CTAP HID message and packet structure:
+        https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html#message-and-packet-structure
+        from Chromium. With this library, WebKit can now turn binaries into messages that CTAP devices could understand.
+        This patch contains the following Chromium files and modifies them to fit into WebKit:
+        https://cs.chromium.org/chromium/src/device/fido/fido_constants.cc?l=1&rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
+        https://cs.chromium.org/chromium/src/device/fido/fido_constants.h?l=1&rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
+        https://cs.chromium.org/chromium/src/device/fido/hid/fido_hid_message.cc?l=1&rcl=387f3725de2842e0e6b7175a9b2ed472b0cf781a
+        https://cs.chromium.org/chromium/src/device/fido/hid/fido_hid_message.h?rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
+        https://cs.chromium.org/chromium/src/device/fido/hid/fido_hid_packet.cc?rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
+        https://cs.chromium.org/chromium/src/device/fido/hid/fido_hid_packet.h?rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
+        https://cs.chromium.org/chromium/src/device/fido/hid/fido_hid_message_unittest.cc?rcl=1efcfbeaf4e4cedf58716e1982b5702770571a75
+
+        Covered by API tests.
+
+        * Modules/webauthn/fido/FidoConstants.cpp: Added.
+        (fido::isFidoHidDeviceCommand):
+        * Modules/webauthn/fido/FidoConstants.h: Added.
+        * Modules/webauthn/fido/FidoHidMessage.cpp: Added.
+        (fido::FidoHidMessage::create):
+        (fido::FidoHidMessage::createFromSerializedData):
+        (fido::FidoHidMessage::messageComplete const):
+        (fido::FidoHidMessage::getMessagePayload const):
+        (fido::FidoHidMessage::popNextPacket):
+        (fido::FidoHidMessage::addContinuationPacket):
+        (fido::FidoHidMessage::numPackets const):
+        (fido::FidoHidMessage::FidoHidMessage):
+        * Modules/webauthn/fido/FidoHidMessage.h: Added.
+        * Modules/webauthn/fido/FidoHidPacket.cpp: Added.
+        (fido::FidoHidPacket::FidoHidPacket):
+        (fido::FidoHidInitPacket::createFromSerializedData):
+        (fido::FidoHidInitPacket::FidoHidInitPacket):
+        (fido::FidoHidInitPacket::getSerializedData const):
+        (fido::FidoHidContinuationPacket::createFromSerializedData):
+        (fido::FidoHidContinuationPacket::FidoHidContinuationPacket):
+        (fido::FidoHidContinuationPacket::getSerializedData const):
+        * Modules/webauthn/fido/FidoHidPacket.h: Added.
+        * Modules/webauthn/fido/FidoParsingUtils.cpp: Added.
+        (fido::getInitPacketData):
+        (fido::getContinuationPacketData):
+        * Modules/webauthn/fido/FidoParsingUtils.h: Added.
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
 2018-10-09  Carlos Eduardo Ramalho  <cadubentzen@gmail.com>
 
         [CoordGraphics] Remove the 'previous backing store' logic
diff --git a/Source/WebCore/Modules/webauthn/fido/FidoConstants.cpp b/Source/WebCore/Modules/webauthn/fido/FidoConstants.cpp
new file mode 100644 (file)
index 0000000..3881fd2
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright (C) 2018 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+#include "FidoConstants.h"
+
+#if ENABLE(WEB_AUTHN)
+
+namespace fido {
+
+bool isFidoHidDeviceCommand(FidoHidDeviceCommand cmd)
+{
+    switch (cmd) {
+    case FidoHidDeviceCommand::kMsg:
+    case FidoHidDeviceCommand::kCbor:
+    case FidoHidDeviceCommand::kInit:
+    case FidoHidDeviceCommand::kPing:
+    case FidoHidDeviceCommand::kCancel:
+    case FidoHidDeviceCommand::kError:
+    case FidoHidDeviceCommand::kKeepAlive:
+    case FidoHidDeviceCommand::kWink:
+    case FidoHidDeviceCommand::kLock:
+        return true;
+    default:
+        return false;
+    }
+}
+
+} // namespace fido
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/fido/FidoConstants.h b/Source/WebCore/Modules/webauthn/fido/FidoConstants.h
new file mode 100644 (file)
index 0000000..b8690f0
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright (C) 2018 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+namespace fido {
+
+// Commands supported by CTAPHID device as specified in
+// https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html#ctaphid-commands
+enum class FidoHidDeviceCommand : uint8_t {
+    kMsg = 0x03,
+    kCbor = 0x10,
+    kInit = 0x06,
+    kPing = 0x01,
+    kCancel = 0x11,
+    kError = 0x3F,
+    kKeepAlive = 0x3B,
+    kWink = 0x08,
+    kLock = 0x04,
+};
+
+bool isFidoHidDeviceCommand(FidoHidDeviceCommand cmd);
+
+// HID transport specific constants.
+const size_t kHidPacketSize = 64;
+const uint32_t kHidBroadcastChannel = 0xffffffff;
+const size_t kHidInitPacketHeaderSize = 7;
+const size_t kHidContinuationPacketHeader = 5;
+const size_t kHidMaxPacketSize = 64;
+const size_t kHidInitPacketDataSize = kHidMaxPacketSize - kHidInitPacketHeaderSize;
+const size_t kHidContinuationPacketDataSize = kHidMaxPacketSize - kHidContinuationPacketHeader;
+
+const uint8_t kHidMaxLockSeconds = 10;
+
+// Messages are limited to an initiation packet and 128 continuation packets.
+const size_t kHidMaxMessageSize = 7609;
+
+} // namespace fido
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/fido/FidoHidMessage.cpp b/Source/WebCore/Modules/webauthn/fido/FidoHidMessage.cpp
new file mode 100644 (file)
index 0000000..395e5ec
--- /dev/null
@@ -0,0 +1,166 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright (C) 2018 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+#include "FidoHidMessage.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include "FidoParsingUtils.h"
+
+namespace fido {
+
+// static
+std::optional<FidoHidMessage> FidoHidMessage::create(uint32_t channelId, FidoHidDeviceCommand type, const Vector<uint8_t>& data)
+{
+    if (data.size() > kHidMaxMessageSize)
+        return std::nullopt;
+
+    switch (type) {
+    case FidoHidDeviceCommand::kPing:
+        break;
+    case FidoHidDeviceCommand::kMsg:
+    case FidoHidDeviceCommand::kCbor: {
+        if (data.isEmpty())
+            return std::nullopt;
+        break;
+    }
+
+    case FidoHidDeviceCommand::kCancel:
+    case FidoHidDeviceCommand::kWink: {
+        if (!data.isEmpty())
+            return std::nullopt;
+        break;
+    }
+    case FidoHidDeviceCommand::kLock: {
+        if (data.size() != 1 || data[0] > kHidMaxLockSeconds)
+            return std::nullopt;
+        break;
+    }
+    case FidoHidDeviceCommand::kInit: {
+        if (data.size() != 8)
+            return std::nullopt;
+        break;
+    }
+    case FidoHidDeviceCommand::kKeepAlive:
+    case FidoHidDeviceCommand::kError:
+        if (data.size() != 1)
+            return std::nullopt;
+    }
+
+    return FidoHidMessage(channelId, type, data);
+}
+
+// static
+std::optional<FidoHidMessage> FidoHidMessage::createFromSerializedData(const Vector<uint8_t>& serializedData)
+{
+    size_t remainingSize = 0;
+    if (serializedData.size() > kHidPacketSize || serializedData.size() < kHidInitPacketHeaderSize)
+        return std::nullopt;
+
+    auto initPacket = FidoHidInitPacket::createFromSerializedData(serializedData, &remainingSize);
+
+    if (!initPacket)
+        return std::nullopt;
+
+    return FidoHidMessage(WTFMove(initPacket), remainingSize);
+}
+
+bool FidoHidMessage::messageComplete() const
+{
+    return !m_remainingSize;
+}
+
+Vector<uint8_t> FidoHidMessage::getMessagePayload() const
+{
+    Vector<uint8_t> data;
+    size_t dataSize = 0;
+    for (const auto& packet : m_packets)
+        dataSize += packet->getPacketPayload().size();
+    data.reserveInitialCapacity(dataSize);
+
+    for (const auto& packet : m_packets) {
+        const auto& packet_data = packet->getPacketPayload();
+        data.appendVector(packet_data);
+    }
+
+    return data;
+}
+
+Vector<uint8_t> FidoHidMessage::popNextPacket()
+{
+    if (m_packets.isEmpty())
+        return { };
+
+    Vector<uint8_t> data = m_packets.first()->getSerializedData();
+    m_packets.removeFirst();
+    return data;
+}
+
+bool FidoHidMessage::addContinuationPacket(const Vector<uint8_t>& buf)
+{
+    size_t remainingSize = m_remainingSize;
+    auto contPacket = FidoHidContinuationPacket::createFromSerializedData(buf, &remainingSize);
+
+    // Reject packets with a different channel id.
+    if (!contPacket || m_channelId != contPacket->channelId())
+        return false;
+
+    m_remainingSize = remainingSize;
+    m_packets.append(WTFMove(contPacket));
+    return true;
+}
+
+size_t FidoHidMessage::numPackets() const
+{
+    return m_packets.size();
+}
+
+FidoHidMessage::FidoHidMessage(uint32_t channelId, FidoHidDeviceCommand type, const Vector<uint8_t>& data)
+    : m_channelId(channelId)
+{
+    uint8_t sequence = 0;
+
+    size_t pos = data.size() > kHidInitPacketDataSize ? kHidInitPacketDataSize : data.size();
+    m_packets.append(std::make_unique<FidoHidInitPacket>(channelId, type, getInitPacketData(data), data.size()));
+    for (; pos < data.size(); pos += kHidContinuationPacketDataSize)
+        m_packets.append(std::make_unique<FidoHidContinuationPacket>(channelId, sequence++, getContinuationPacketData(data, pos)));
+}
+
+FidoHidMessage::FidoHidMessage(std::unique_ptr<FidoHidInitPacket> initPacket, size_t remainingSize)
+    : m_remainingSize(remainingSize)
+{
+    m_channelId = initPacket->channelId();
+    m_cmd = initPacket->command();
+    m_packets.append(WTFMove(initPacket));
+}
+
+} // namespace fido
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/fido/FidoHidMessage.h b/Source/WebCore/Modules/webauthn/fido/FidoHidMessage.h
new file mode 100644 (file)
index 0000000..0d9d3fc
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright (C) 2018 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "FidoConstants.h"
+#include "FidoHidPacket.h"
+#include <wtf/Deque.h>
+#include <wtf/Optional.h>
+#include <wtf/Vector.h>
+
+namespace fido {
+
+// Represents HID message format defined by the specification at
+// https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html#message-and-packet-structure
+class WEBCORE_EXPORT FidoHidMessage {
+    WTF_MAKE_NONCOPYABLE(FidoHidMessage);
+public:
+    // Static functions to create CTAP/U2F HID commands.
+    static std::optional<FidoHidMessage> create(uint32_t channelId, FidoHidDeviceCommand, const Vector<uint8_t>& data);
+
+    // Reconstruct a message from serialized message data.
+    static std::optional<FidoHidMessage> createFromSerializedData(const Vector<uint8_t>&);
+
+    FidoHidMessage(FidoHidMessage&& that) = default;
+    FidoHidMessage& operator=(FidoHidMessage&& other) = default;
+
+    bool messageComplete() const;
+    Vector<uint8_t> getMessagePayload() const;
+    // Pop front of queue with next packet.
+    Vector<uint8_t> popNextPacket();
+    // Adds a continuation packet to the packet list, from the serialized
+    // response value.
+    bool addContinuationPacket(const Vector<uint8_t>&);
+
+    size_t numPackets() const;
+    uint32_t channelId() const { return m_channelId; }
+    FidoHidDeviceCommand cmd() const { return m_cmd; }
+    const Deque<std::unique_ptr<FidoHidPacket>>& getPacketsForTesting() const { return m_packets; }
+
+private:
+    FidoHidMessage(uint32_t channelId, FidoHidDeviceCommand, const Vector<uint8_t>& data);
+    FidoHidMessage(std::unique_ptr<FidoHidInitPacket>, size_t remainingSize);
+
+    uint32_t m_channelId = kHidBroadcastChannel;
+    FidoHidDeviceCommand m_cmd = FidoHidDeviceCommand::kMsg;
+    Deque<std::unique_ptr<FidoHidPacket>> m_packets;
+    size_t m_remainingSize = 0;
+};
+
+} // namespace fido
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/fido/FidoHidPacket.cpp b/Source/WebCore/Modules/webauthn/fido/FidoHidPacket.cpp
new file mode 100644 (file)
index 0000000..55b7b2d
--- /dev/null
@@ -0,0 +1,157 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright (C) 2018 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+#include "FidoHidPacket.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include <algorithm>
+
+namespace fido {
+
+FidoHidPacket::FidoHidPacket(Vector<uint8_t>&& data, uint32_t channelId)
+    : m_data(WTFMove(data))
+    , m_channelId(channelId)
+{
+}
+
+// static
+std::unique_ptr<FidoHidInitPacket> FidoHidInitPacket::createFromSerializedData(const Vector<uint8_t>& serialized, size_t* remainingSize)
+{
+    if (!remainingSize || serialized.size() != kHidPacketSize)
+        return nullptr;
+
+    size_t index = 0;
+    auto channelId = (serialized[index++] & 0xff) << 24;
+    channelId |= (serialized[index++] & 0xff) << 16;
+    channelId |= (serialized[index++] & 0xff) << 8;
+    channelId |= serialized[index++] & 0xff;
+
+    auto command = static_cast<FidoHidDeviceCommand>(serialized[index++] & 0x7f);
+    if (!isFidoHidDeviceCommand(command))
+        return nullptr;
+
+    uint16_t payloadSize = serialized[index++] << 8;
+    payloadSize |= serialized[index++];
+
+    // Check to see if payload is less than maximum size and padded with 0s.
+    uint16_t dataSize = std::min(payloadSize, static_cast<uint16_t>(kHidPacketSize - index));
+
+    // Update remaining size to determine the payload size of follow on packets.
+    *remainingSize = payloadSize - dataSize;
+
+    auto data = Vector<uint8_t>();
+    data.append(serialized.begin() + index, dataSize);
+
+    return std::make_unique<FidoHidInitPacket>(channelId, command, WTFMove(data), payloadSize);
+}
+
+// U2F Initialization packet is defined as:
+// Offset Length
+// 0      4       Channel ID
+// 4      1       Command ID
+// 5      1       High order packet payload size
+// 6      1       Low order packet payload size
+// 7      (s-7)   Payload data
+FidoHidInitPacket::FidoHidInitPacket(uint32_t channelId, FidoHidDeviceCommand cmd, Vector<uint8_t>&& data, uint16_t payloadLength)
+    : FidoHidPacket(WTFMove(data), channelId)
+    , m_command(cmd)
+    , m_payloadLength(payloadLength)
+{
+}
+
+Vector<uint8_t> FidoHidInitPacket::getSerializedData() const
+{
+    Vector<uint8_t> serialized;
+    serialized.reserveInitialCapacity(kHidPacketSize);
+    serialized.append((m_channelId >> 24) & 0xff);
+    serialized.append((m_channelId >> 16) & 0xff);
+    serialized.append((m_channelId >> 8) & 0xff);
+    serialized.append(m_channelId & 0xff);
+    serialized.append(static_cast<uint8_t>(m_command) | 0x80);
+    serialized.append((m_payloadLength >> 8) & 0xff);
+    serialized.append(m_payloadLength & 0xff);
+    serialized.append(m_data.begin(), m_data.size());
+    serialized.grow(kHidPacketSize);
+
+    return serialized;
+}
+
+// static
+std::unique_ptr<FidoHidContinuationPacket> FidoHidContinuationPacket::createFromSerializedData(const Vector<uint8_t>& serialized, size_t* remainingSize)
+{
+    if (!remainingSize || serialized.size() != kHidPacketSize)
+        return nullptr;
+
+    size_t index = 0;
+    auto channelId = (serialized[index++] & 0xff) << 24;
+    channelId |= (serialized[index++] & 0xff) << 16;
+    channelId |= (serialized[index++] & 0xff) << 8;
+    channelId |= serialized[index++] & 0xff;
+    auto sequence = serialized[index++];
+
+    // Check to see if packet payload is less than maximum size and padded with 0s.
+    size_t dataSize = std::min(*remainingSize, kHidPacketSize - index);
+    *remainingSize -= dataSize;
+    auto data = Vector<uint8_t>();
+    data.append(serialized.begin() + index, dataSize);
+
+    return std::make_unique<FidoHidContinuationPacket>(channelId, sequence, WTFMove(data));
+}
+
+// U2F Continuation packet is defined as:
+// Offset Length
+// 0      4       Channel ID
+// 4      1       Packet sequence 0x00..0x7f
+// 5      (s-5)   Payload data
+FidoHidContinuationPacket::FidoHidContinuationPacket(const uint32_t channelId, const uint8_t sequence, Vector<uint8_t>&& data)
+    : FidoHidPacket(WTFMove(data), channelId)
+    , m_sequence(sequence)
+{
+}
+
+Vector<uint8_t> FidoHidContinuationPacket::getSerializedData() const
+{
+    Vector<uint8_t> serialized;
+    serialized.reserveInitialCapacity(kHidPacketSize);
+    serialized.append((m_channelId >> 24) & 0xff);
+    serialized.append((m_channelId >> 16) & 0xff);
+    serialized.append((m_channelId >> 8) & 0xff);
+    serialized.append(m_channelId & 0xff);
+    serialized.append(m_sequence);
+    serialized.append(m_data.begin(), m_data.size());
+    serialized.grow(kHidPacketSize);
+
+    return serialized;
+}
+
+} // namespace fido
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/fido/FidoHidPacket.h b/Source/WebCore/Modules/webauthn/fido/FidoHidPacket.h
new file mode 100644 (file)
index 0000000..18fcade
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright (C) 2018 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include "FidoConstants.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace fido {
+
+// HID Packets are defined by the specification at
+// https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html#message-and-packet-structure
+// Packets are one of two types, initialization packets and continuation
+// packets. HID Packets have header information and a payload. If a
+// FidoHidInitPacket cannot store the entire payload, further payload
+// information is stored in HidContinuationPackets.
+class WEBCORE_EXPORT FidoHidPacket {
+    WTF_MAKE_NONCOPYABLE(FidoHidPacket);
+public:
+    FidoHidPacket(Vector<uint8_t>&& data, uint32_t channelId);
+    virtual ~FidoHidPacket() = default;
+
+    virtual Vector<uint8_t> getSerializedData() const = 0;
+    const Vector<uint8_t>& getPacketPayload() const { return m_data; }
+    uint32_t channelId() const { return m_channelId; }
+
+protected:
+    FidoHidPacket();
+
+    Vector<uint8_t> m_data;
+    uint32_t m_channelId = kHidBroadcastChannel;
+};
+
+// FidoHidInitPacket, based on the CTAP specification consists of a header with
+// data that is serialized into a IOBuffer. A channel identifier is allocated by
+// the CTAP device to ensure its system-wide uniqueness. Command identifiers
+// determine the type of message the packet corresponds to. Payload length
+// is the length of the entire message payload, and the data is only the portion
+// of the payload that will fit into the HidInitPacket.
+class WEBCORE_EXPORT FidoHidInitPacket : public FidoHidPacket {
+public:
+    // Creates a packet from the serialized data of an initialization packet. As
+    // this is the first packet, the payload length of the entire message will be
+    // included within the serialized data. Remaining size will be returned to
+    // inform the callee how many additional packets to expect.
+    static std::unique_ptr<FidoHidInitPacket> createFromSerializedData(const Vector<uint8_t>&, size_t* remainingSize);
+
+    FidoHidInitPacket(uint32_t channelId, FidoHidDeviceCommand, Vector<uint8_t>&& data, uint16_t payloadLength);
+
+    Vector<uint8_t> getSerializedData() const final;
+    FidoHidDeviceCommand command() const { return m_command; }
+    uint16_t payloadLength() const { return m_payloadLength; }
+
+private:
+    FidoHidDeviceCommand m_command;
+    uint16_t m_payloadLength;
+};
+
+// FidoHidContinuationPacket, based on the CTAP Specification consists of a
+// header with data that is serialized into an IOBuffer. The channel identifier
+// will be identical to the identifier in all other packets of the message. The
+// packet sequence will be the sequence number of this particular packet, from
+// 0x00 to 0x7f.
+class WEBCORE_EXPORT FidoHidContinuationPacket : public FidoHidPacket {
+public:
+    // Creates a packet from the serialized data of a continuation packet. As an
+    // HidInitPacket would have arrived earlier with the total payload size,
+    // the remaining size should be passed to inform the packet of how much data
+    // to expect.
+    static std::unique_ptr<FidoHidContinuationPacket> createFromSerializedData(const Vector<uint8_t>&, size_t* remainingSize);
+
+    FidoHidContinuationPacket(uint32_t channelId, uint8_t sequence, Vector<uint8_t>&& data);
+
+    Vector<uint8_t> getSerializedData() const final;
+    uint8_t sequence() const { return m_sequence; }
+
+private:
+    uint8_t m_sequence;
+};
+
+} // namespace fido
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/fido/FidoParsingUtils.cpp b/Source/WebCore/Modules/webauthn/fido/FidoParsingUtils.cpp
new file mode 100644 (file)
index 0000000..f774a15
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FidoParsingUtils.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include "FidoConstants.h"
+
+namespace fido {
+
+Vector<uint8_t> getInitPacketData(const Vector<uint8_t>& data)
+{
+    Vector<uint8_t> result;
+    result.append(data.data(), data.size() > kHidInitPacketDataSize ? kHidInitPacketDataSize : data.size());
+    return result;
+}
+
+Vector<uint8_t> getContinuationPacketData(const Vector<uint8_t>& data, size_t beginPosition)
+{
+    if (beginPosition > data.size())
+        return { };
+
+    Vector<uint8_t> result;
+    result.append(data.data() + beginPosition, data.size() > kHidContinuationPacketDataSize + beginPosition ? kHidContinuationPacketDataSize : data.size() - beginPosition);
+    return result;
+}
+
+} // namespace fido
+
+#endif // ENABLE(WEB_AUTHN)
diff --git a/Source/WebCore/Modules/webauthn/fido/FidoParsingUtils.h b/Source/WebCore/Modules/webauthn/fido/FidoParsingUtils.h
new file mode 100644 (file)
index 0000000..f41f20f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_AUTHN)
+
+#include <wtf/Vector.h>
+
+namespace fido {
+
+Vector<uint8_t> getInitPacketData(const Vector<uint8_t>&);
+Vector<uint8_t> getContinuationPacketData(const Vector<uint8_t>&, size_t beginPosition);
+
+} // namespace fido
+
+#endif // ENABLE(WEB_AUTHN)
index b46e4e2..4caef4a 100644 (file)
@@ -254,6 +254,10 @@ Modules/webauthn/PublicKeyCredential.cpp
 Modules/webauthn/cbor/CBORReader.cpp
 Modules/webauthn/cbor/CBORValue.cpp
 Modules/webauthn/cbor/CBORWriter.cpp
+Modules/webauthn/fido/FidoConstants.cpp
+Modules/webauthn/fido/FidoHidMessage.cpp
+Modules/webauthn/fido/FidoHidPacket.cpp
+Modules/webauthn/fido/FidoParsingUtils.cpp
 
 Modules/webdatabase/ChangeVersionWrapper.cpp
 Modules/webdatabase/DOMWindowWebDatabase.cpp
index 06faeca..ada26e0 100644 (file)
                57303C4620105D2F00355965 /* AuthenticatorCoordinator.h in Headers */ = {isa = PBXBuildFile; fileRef = 57303C4320105B3D00355965 /* AuthenticatorCoordinator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                573489391DAC6B6E00DC0667 /* CryptoAlgorithmParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 573489381DAC6B6D00DC0667 /* CryptoAlgorithmParameters.h */; };
                5739E12F1DAC7F7800E14383 /* JSCryptoAlgorithmParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 5739E12E1DAC7F7800E14383 /* JSCryptoAlgorithmParameters.h */; };
+               573F5332216806E10045587A /* FidoHidMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 57BAF28A2167D303008E954E /* FidoHidMessage.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               573F533721680D150045587A /* FidoParsingUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 573F533521680D140045587A /* FidoParsingUtils.h */; };
                574F55E1204F3B23002948C6 /* COSEConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 574F55DC204F3732002948C6 /* COSEConstants.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5750A9751E68D00000705C4A /* CryptoKeyEC.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9731E68D00000705C4A /* CryptoKeyEC.h */; };
                5750A97E1E6A13EF00705C4A /* CryptoAlgorithmEcKeyParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A97D1E6A13EF00705C4A /* CryptoAlgorithmEcKeyParams.h */; };
                57B5F7F91E5BE84000F34F90 /* CryptoAlgorithmAES_GCM.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B5F7F71E5BE84000F34F90 /* CryptoAlgorithmAES_GCM.h */; };
                57B5F8091E5D1A9800F34F90 /* CryptoAlgorithmAesGcmParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B5F8081E5D1A9800F34F90 /* CryptoAlgorithmAesGcmParams.h */; };
                57B5F8101E5E2A4E00F34F90 /* JSAesGcmParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B5F80B1E5D22DA00F34F90 /* JSAesGcmParams.h */; };
+               57BAF28C2167D316008E954E /* FidoConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 578A4C0B2167D29600D08F34 /* FidoConstants.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               57BAF28E2167D339008E954E /* FidoHidPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 578A4C0A2167D29600D08F34 /* FidoHidPacket.h */; settings = {ATTRIBUTES = (Private, ); }; };
                57C7A68C1E56967500C67D71 /* BasicCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 57C7A68B1E56967500C67D71 /* BasicCredential.h */; settings = {ATTRIBUTES = (Private, ); }; };
                57C7A69F1E57917800C67D71 /* JSBasicCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = 57C7A69D1E57910D00C67D71 /* JSBasicCredential.h */; };
                57D0018D1DD5413200ED19D9 /* JSCryptoKeyUsage.h in Headers */ = {isa = PBXBuildFile; fileRef = 57D0018C1DD5413200ED19D9 /* JSCryptoKeyUsage.h */; };
                573489381DAC6B6D00DC0667 /* CryptoAlgorithmParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmParameters.h; sourceTree = "<group>"; };
                5739E12E1DAC7F7800E14383 /* JSCryptoAlgorithmParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCryptoAlgorithmParameters.h; sourceTree = "<group>"; };
                5739E1301DAC7FD100E14383 /* JSCryptoAlgorithmParameters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCryptoAlgorithmParameters.cpp; sourceTree = "<group>"; };
+               573F533521680D140045587A /* FidoParsingUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FidoParsingUtils.h; sourceTree = "<group>"; };
+               573F533621680D150045587A /* FidoParsingUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FidoParsingUtils.cpp; sourceTree = "<group>"; };
                574AC7531DAC367D00E9744C /* CryptoAlgorithmParameters.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CryptoAlgorithmParameters.idl; sourceTree = "<group>"; };
                574D42791D594FF6002CF50E /* GlobalCrypto.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GlobalCrypto.idl; sourceTree = "<group>"; };
                574F55DC204F3732002948C6 /* COSEConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COSEConstants.h; sourceTree = "<group>"; };
                5778BD801DA4733E009E3009 /* SubtleCrypto.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SubtleCrypto.idl; sourceTree = "<group>"; };
                5778BD811DA4802C009E3009 /* SubtleCrypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SubtleCrypto.h; sourceTree = "<group>"; };
                5778BD831DA4817B009E3009 /* SubtleCrypto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SubtleCrypto.cpp; sourceTree = "<group>"; };
+               578A4C082167D29500D08F34 /* FidoHidMessage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FidoHidMessage.cpp; sourceTree = "<group>"; };
+               578A4C092167D29600D08F34 /* FidoHidPacket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FidoHidPacket.cpp; sourceTree = "<group>"; };
+               578A4C0A2167D29600D08F34 /* FidoHidPacket.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FidoHidPacket.h; sourceTree = "<group>"; };
+               578A4C0B2167D29600D08F34 /* FidoConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FidoConstants.h; sourceTree = "<group>"; };
                5790996B1ECD23DA00FC0768 /* CryptoAlgorithmRSA_PSS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmRSA_PSS.h; sourceTree = "<group>"; };
                5790996C1ECD23DA00FC0768 /* CryptoAlgorithmRSA_PSS.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmRSA_PSS.cpp; sourceTree = "<group>"; };
                57957CA61E971DE0008072AB /* CryptoAlgorithmHKDF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmHKDF.cpp; sourceTree = "<group>"; };
                57B5F80A1E5D22DA00F34F90 /* JSAesGcmParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAesGcmParams.cpp; sourceTree = "<group>"; };
                57B5F80B1E5D22DA00F34F90 /* JSAesGcmParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSAesGcmParams.h; sourceTree = "<group>"; };
                57B5F80D1E5D2F2D00F34F90 /* CryptoAlgorithmAES_GCMMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmAES_GCMMac.cpp; sourceTree = "<group>"; };
+               57BAF2872167D2F7008E954E /* FidoConstants.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FidoConstants.cpp; sourceTree = "<group>"; };
+               57BAF28A2167D303008E954E /* FidoHidMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FidoHidMessage.h; sourceTree = "<group>"; };
                57C7A6891E56946D00C67D71 /* BasicCredential.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BasicCredential.idl; sourceTree = "<group>"; };
                57C7A68B1E56967500C67D71 /* BasicCredential.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BasicCredential.h; sourceTree = "<group>"; };
                57C7A6931E578ACA00C67D71 /* BasicCredential.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BasicCredential.cpp; sourceTree = "<group>"; };
                        path = cbor;
                        sourceTree = "<group>";
                };
+               578A4BFA2166AE0000D08F34 /* fido */ = {
+                       isa = PBXGroup;
+                       children = (
+                               57BAF2872167D2F7008E954E /* FidoConstants.cpp */,
+                               578A4C0B2167D29600D08F34 /* FidoConstants.h */,
+                               578A4C082167D29500D08F34 /* FidoHidMessage.cpp */,
+                               57BAF28A2167D303008E954E /* FidoHidMessage.h */,
+                               578A4C092167D29600D08F34 /* FidoHidPacket.cpp */,
+                               578A4C0A2167D29600D08F34 /* FidoHidPacket.h */,
+                               573F533621680D150045587A /* FidoParsingUtils.cpp */,
+                               573F533521680D140045587A /* FidoParsingUtils.h */,
+                       );
+                       path = fido;
+                       sourceTree = "<group>";
+               };
                57C7A6881E56946D00C67D71 /* credentialmanagement */ = {
                        isa = PBXGroup;
                        children = (
                        isa = PBXGroup;
                        children = (
                                57303BB32006C6ED00355965 /* cbor */,
+                               578A4BFA2166AE0000D08F34 /* fido */,
                                57303C272009B2FC00355965 /* AuthenticatorAssertionResponse.h */,
                                57303C292009B2FC00355965 /* AuthenticatorAssertionResponse.idl */,
                                57303C1B2009A98600355965 /* AuthenticatorAttestationResponse.h */,
                                84730D8D1248F0B300D3A9C9 /* FETurbulence.h in Headers */,
                                FD31609512B026F700C1A359 /* FFTConvolver.h in Headers */,
                                FD31609712B026F700C1A359 /* FFTFrame.h in Headers */,
+                               57BAF28C2167D316008E954E /* FidoConstants.h in Headers */,
+                               573F5332216806E10045587A /* FidoHidMessage.h in Headers */,
+                               57BAF28E2167D339008E954E /* FidoHidPacket.h in Headers */,
+                               573F533721680D150045587A /* FidoParsingUtils.h in Headers */,
                                976D6C81122B8A3D001FD1F7 /* File.h in Headers */,
                                838F86DA1F509E7400E8CFC5 /* FileCallback.h in Headers */,
                                066C772B0AB603B700238CC4 /* FileChooser.h in Headers */,
index e87421e..fa891ca 100644 (file)
@@ -1,3 +1,15 @@
+2018-10-09  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebAuthN] Import CTAP HID message and packet structure from Chromium
+        https://bugs.webkit.org/show_bug.cgi?id=189289
+        <rdar://problem/44120310>
+
+        Reviewed by Brent Fulgham.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebCore/FidoHidMessageTest.cpp: Added.
+        (TestWebKitAPI::TEST):
+
 2018-10-09  Chris Dumez  <cdumez@apple.com>
 
         PSON: Doing a cross-site navigation via the URL bar does not swap process on iOS
index 4341c47..83fef46 100644 (file)
                5769C50B1D9B0002000847FB /* SerializedCryptoKeyWrap.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5769C50A1D9B0001000847FB /* SerializedCryptoKeyWrap.mm */; };
                578CBD67204FB2C80083B9F2 /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 578CBD66204FB2C70083B9F2 /* LocalAuthentication.framework */; };
                57901FB11CAF142D00ED64F9 /* LoadInvalidURLRequest.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 57901FB01CAF141C00ED64F9 /* LoadInvalidURLRequest.html */; };
+               579651E7216BFDED006EBFE5 /* FidoHidMessageTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 579651E6216BFD53006EBFE5 /* FidoHidMessageTest.cpp */; };
                5797FE311EB15A6800B2F4A0 /* NavigationClientDefaultCrypto.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5797FE2F1EB15A5F00B2F4A0 /* NavigationClientDefaultCrypto.cpp */; };
                5797FE331EB15AB100B2F4A0 /* navigation-client-default-crypto.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5797FE321EB15A8900B2F4A0 /* navigation-client-default-crypto.html */; };
                57C3FA661F7C248F009D4B80 /* WeakPtr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1CB9BC371A67482300FE5678 /* WeakPtr.cpp */; };
                57901FAC1CAF12C200ED64F9 /* LoadInvalidURLRequest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LoadInvalidURLRequest.mm; sourceTree = "<group>"; };
                57901FAE1CAF137100ED64F9 /* LoadInvalidURLRequest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LoadInvalidURLRequest.mm; sourceTree = "<group>"; };
                57901FB01CAF141C00ED64F9 /* LoadInvalidURLRequest.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = LoadInvalidURLRequest.html; sourceTree = "<group>"; };
+               579651E6216BFD53006EBFE5 /* FidoHidMessageTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FidoHidMessageTest.cpp; sourceTree = "<group>"; };
                5797FE2F1EB15A5F00B2F4A0 /* NavigationClientDefaultCrypto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NavigationClientDefaultCrypto.cpp; sourceTree = "<group>"; };
                5797FE321EB15A8900B2F4A0 /* navigation-client-default-crypto.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "navigation-client-default-crypto.html"; sourceTree = "<group>"; };
                5798E2AF1CAF5C2800C5CBA0 /* ProvisionalURLNotChange.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ProvisionalURLNotChange.mm; sourceTree = "<group>"; };
                                260BA57A1B1D2EE2004FA07C /* DFAHelpers.h */,
                                26F6E1EF1ADC749B00DE696B /* DFAMinimizer.cpp */,
                                3151180F1DB1ADD500176304 /* ExtendedColor.cpp */,
+                               579651E6216BFD53006EBFE5 /* FidoHidMessageTest.cpp */,
                                7A32D7491F02151500162C44 /* FileMonitor.cpp */,
                                41973B5A1AF2286A006C7B36 /* FileSystem.cpp */,
                                7A909A701D877475007E10F8 /* FloatPoint.cpp */,
                                CDA29B2920FD2A9900F15CED /* ExitFullscreenOnEnterPiP.mm in Sources */,
                                315118101DB1AE4000176304 /* ExtendedColor.cpp in Sources */,
                                7CCE7EF11A411AE600447C4C /* FailedLoad.cpp in Sources */,
+                               579651E7216BFDED006EBFE5 /* FidoHidMessageTest.cpp in Sources */,
                                7A32D74A1F02151500162C44 /* FileMonitor.cpp in Sources */,
                                7C83E04F1D0A641800FEBCF3 /* FileSystem.cpp in Sources */,
                                7CCE7EF31A411AE600447C4C /* Find.cpp in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/FidoHidMessageTest.cpp b/Tools/TestWebKitAPI/Tests/WebCore/FidoHidMessageTest.cpp
new file mode 100644 (file)
index 0000000..738de44
--- /dev/null
@@ -0,0 +1,213 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright (C) 2018 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+
+#if ENABLE(WEB_AUTHN)
+
+#include <WebCore/FidoConstants.h>
+#include <WebCore/FidoHidMessage.h>
+#include <WebCore/FidoHidPacket.h>
+#include <wtf/Deque.h>
+#include <wtf/Vector.h>
+
+namespace TestWebKitAPI {
+
+using namespace fido;
+
+// Packets should be 64 bytes + 1 report ID byte.
+TEST(FidoHidMessageTest, TestPacketSize)
+{
+    uint32_t channelId = 0x05060708;
+    Vector<uint8_t> data;
+
+    auto initPacket = std::make_unique<FidoHidInitPacket>(channelId, FidoHidDeviceCommand::kInit, Vector<uint8_t>(data), data.size());
+    EXPECT_EQ(64u, initPacket->getSerializedData().size());
+
+    auto continuationPacket = std::make_unique<FidoHidContinuationPacket>(channelId, 0, WTFMove(data));
+    EXPECT_EQ(64u, continuationPacket->getSerializedData().size());
+}
+
+/*
+ * U2f Init Packets are of the format:
+ * Byte 0:    0
+ * Byte 1-4:  Channel ID
+ * Byte 5:    Command byte
+ * Byte 6-7:  Big Endian size of data
+ * Byte 8-n:  Data block
+ *
+ * Remaining buffer is padded with 0
+ */
+TEST(FidoHidMessageTest, TestPacketData)
+{
+    uint32_t channelId = 0xF5060708;
+    Vector<uint8_t> data {10, 11};
+    FidoHidDeviceCommand cmd = FidoHidDeviceCommand::kWink;
+    auto initPacket = std::make_unique<FidoHidInitPacket>(channelId, cmd, Vector<uint8_t>(data), data.size());
+    size_t index = 0;
+
+    Vector<uint8_t> serialized = initPacket->getSerializedData();
+    EXPECT_EQ((channelId >> 24) & 0xff, serialized[index++]);
+    EXPECT_EQ((channelId >> 16) & 0xff, serialized[index++]);
+    EXPECT_EQ((channelId >> 8) & 0xff, serialized[index++]);
+    EXPECT_EQ(channelId & 0xff, serialized[index++]);
+    EXPECT_EQ(static_cast<uint8_t>(cmd), serialized[index++] & 0x7f);
+
+    EXPECT_EQ(data.size() >> 8, serialized[index++]);
+    EXPECT_EQ(data.size() & 0xff, serialized[index++]);
+    EXPECT_EQ(data[0], serialized[index++]);
+    EXPECT_EQ(data[1], serialized[index++]);
+    for (; index < serialized.size(); index++)
+        EXPECT_EQ(0, serialized[index]) << "mismatch at index " << index;
+}
+
+TEST(FidoHidMessageTest, TestPacketConstructors)
+{
+    uint32_t channelId = 0x05060708;
+    Vector<uint8_t> data {10, 11};
+    FidoHidDeviceCommand cmd = FidoHidDeviceCommand::kWink;
+    size_t length = data.size();
+    auto origPacket = std::make_unique<FidoHidInitPacket>(channelId, cmd, WTFMove(data), length);
+
+    size_t payloadLength = static_cast<size_t>(origPacket->payloadLength());
+    Vector<uint8_t> origData = origPacket->getSerializedData();
+
+    auto reconstructedPacket = FidoHidInitPacket::createFromSerializedData(origData, &payloadLength);
+    EXPECT_EQ(origPacket->command(), reconstructedPacket->command());
+    EXPECT_EQ(origPacket->payloadLength(), reconstructedPacket->payloadLength());
+    EXPECT_EQ(origPacket->getPacketPayload(), reconstructedPacket->getPacketPayload());
+
+    EXPECT_EQ(channelId, reconstructedPacket->channelId());
+
+    ASSERT_EQ(origPacket->getSerializedData().size(), reconstructedPacket->getSerializedData().size());
+    for (size_t index = 0; index < origPacket->getSerializedData().size(); ++index)
+        EXPECT_EQ(origPacket->getSerializedData()[index], reconstructedPacket->getSerializedData()[index]) << "mismatch at index " << index;
+}
+
+TEST(FidoHidMessageTest, TestMaxLengthPacketConstructors)
+{
+    uint32_t channelId = 0xAAABACAD;
+    Vector<uint8_t> data;
+    for (size_t i = 0; i < kHidMaxMessageSize; ++i)
+        data.append(static_cast<uint8_t>(i % 0xff));
+
+    auto origMsg = FidoHidMessage::create(channelId, FidoHidDeviceCommand::kMsg, data);
+    ASSERT_TRUE(origMsg);
+
+    const auto& originalMsgPackets = origMsg->getPacketsForTesting();
+    auto it = originalMsgPackets.begin();
+    auto msgData = (*it)->getSerializedData();
+    auto newMsg = FidoHidMessage::createFromSerializedData(msgData);
+    ++it;
+
+    for (; it != originalMsgPackets.end(); ++it) {
+        msgData = (*it)->getSerializedData();
+        EXPECT_TRUE(newMsg->addContinuationPacket(msgData));
+    }
+
+    auto origIt = originalMsgPackets.begin();
+    const auto& newMsgPackets = newMsg->getPacketsForTesting();
+    auto newMsgIt = newMsgPackets.begin();
+
+    EXPECT_EQ(origMsg->numPackets(), newMsg->numPackets());
+    for (; origIt != originalMsgPackets.end() || newMsgIt != newMsgPackets.end(); ++origIt, ++newMsgIt) {
+        EXPECT_EQ((*origIt)->getPacketPayload(), (*newMsgIt)->getPacketPayload());
+
+        EXPECT_EQ((*origIt)->channelId(), (*newMsgIt)->channelId());
+
+        ASSERT_EQ((*origIt)->getSerializedData().size(), (*newMsgIt)->getSerializedData().size());
+        for (size_t index = 0; index < (*origIt)->getSerializedData().size(); ++index)
+            EXPECT_EQ((*origIt)->getSerializedData()[index], (*newMsgIt)->getSerializedData()[index]) << "mismatch at index " << index;
+    }
+}
+
+TEST(FidoHidMessageTest, TestMessagePartitoning)
+{
+    uint32_t channelId = 0x01010203;
+    Vector<uint8_t> data(kHidInitPacketDataSize + 1);
+    auto twoPacketMessage = FidoHidMessage::create(channelId, FidoHidDeviceCommand::kPing, data);
+    ASSERT_TRUE(twoPacketMessage);
+    EXPECT_EQ(2U, twoPacketMessage->numPackets());
+
+    data.resize(kHidInitPacketDataSize);
+    auto onePacketMessage = FidoHidMessage::create(channelId, FidoHidDeviceCommand::kPing, data);
+    ASSERT_TRUE(onePacketMessage);
+    EXPECT_EQ(1U, onePacketMessage->numPackets());
+
+    data.resize(kHidInitPacketDataSize + kHidContinuationPacketDataSize + 1);
+    auto threePacketMessage = FidoHidMessage::create(channelId, FidoHidDeviceCommand::kPing, data);
+    ASSERT_TRUE(threePacketMessage);
+    EXPECT_EQ(3U, threePacketMessage->numPackets());
+}
+
+TEST(FidoHidMessageTest, TestMaxSize)
+{
+    uint32_t channelId = 0x00010203;
+    Vector<uint8_t> data(kHidMaxMessageSize + 1);
+    auto oversizeMessage = FidoHidMessage::create(channelId, FidoHidDeviceCommand::kPing, data);
+    EXPECT_FALSE(oversizeMessage);
+}
+
+TEST(FidoHidMessageTest, TestDeconstruct)
+{
+    uint32_t channelId = 0x0A0B0C0D;
+    Vector<uint8_t> data(kHidMaxMessageSize, 0x7F);
+    auto filledMessage = FidoHidMessage::create(channelId, FidoHidDeviceCommand::kPing, data);
+    ASSERT_TRUE(filledMessage);
+    EXPECT_EQ(data, filledMessage->getMessagePayload());
+}
+
+TEST(FidoHidMessageTest, TestDeserialize)
+{
+    uint32_t channelId = 0x0A0B0C0D;
+    Vector<uint8_t> data(kHidMaxMessageSize);
+
+    auto origMessage = FidoHidMessage::create(channelId, FidoHidDeviceCommand::kPing, data);
+    ASSERT_TRUE(origMessage);
+
+    Deque<Vector<uint8_t>> origList;
+    auto buf = origMessage->popNextPacket();
+    origList.append(buf);
+
+    auto newMessage = FidoHidMessage::createFromSerializedData(buf);
+    while (!newMessage->messageComplete()) {
+        buf = origMessage->popNextPacket();
+        origList.append(buf);
+        newMessage->addContinuationPacket(buf);
+    }
+
+    while (!(buf = newMessage->popNextPacket()).isEmpty()) {
+        EXPECT_EQ(buf, origList.first());
+        origList.removeFirst();
+    }
+}
+
+} // namespace TestWebKitAPI
+
+#endif // ENABLE(WEB_AUTHN)