blob: b12daefee14e512b4ff4a74a1261041d7359d6d8 [file] [log] [blame]
// 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"
#include <wtf/Optional.h>
#include <wtf/Vector.h>
namespace fido {
// static
Optional<FidoHidMessage> FidoHidMessage::create(uint32_t channelId, FidoHidDeviceCommand type, const Vector<uint8_t>& data)
{
if (data.size() > kHidMaxMessageSize)
return WTF::nullopt;
switch (type) {
case FidoHidDeviceCommand::kPing:
break;
case FidoHidDeviceCommand::kMsg:
case FidoHidDeviceCommand::kCbor: {
if (data.isEmpty())
return WTF::nullopt;
break;
}
case FidoHidDeviceCommand::kCancel:
case FidoHidDeviceCommand::kWink: {
if (!data.isEmpty())
return WTF::nullopt;
break;
}
case FidoHidDeviceCommand::kLock: {
if (data.size() != 1 || data[0] > kHidMaxLockSeconds)
return WTF::nullopt;
break;
}
case FidoHidDeviceCommand::kInit: {
if (data.size() != 8)
return WTF::nullopt;
break;
}
case FidoHidDeviceCommand::kKeepAlive:
case FidoHidDeviceCommand::kError:
if (data.size() != 1)
return WTF::nullopt;
}
return FidoHidMessage(channelId, type, data);
}
// static
Optional<FidoHidMessage> FidoHidMessage::createFromSerializedData(const Vector<uint8_t>& serializedData)
{
size_t remainingSize = 0;
if (serializedData.size() > kHidPacketSize || serializedData.size() < kHidInitPacketHeaderSize)
return WTF::nullopt;
auto initPacket = FidoHidInitPacket::createFromSerializedData(serializedData, &remainingSize);
if (!initPacket)
return WTF::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)
, m_cmd(type)
{
uint8_t sequence = 0;
size_t pos = data.size() > kHidInitPacketDataSize ? kHidInitPacketDataSize : data.size();
m_packets.append(makeUnique<FidoHidInitPacket>(channelId, type, getInitPacketData(data), data.size()));
for (; pos < data.size(); pos += kHidContinuationPacketDataSize)
m_packets.append(makeUnique<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)