[WebAuthN] Import CTAP HID message and packet structure from Chromium
[WebKit-https.git] / Source / WebCore / Modules / webauthn / fido / FidoHidPacket.cpp
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Copyright (C) 2018 Apple Inc. All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //    * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //    * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //    * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "config.h"
31 #include "FidoHidPacket.h"
32
33 #if ENABLE(WEB_AUTHN)
34
35 #include <algorithm>
36
37 namespace fido {
38
39 FidoHidPacket::FidoHidPacket(Vector<uint8_t>&& data, uint32_t channelId)
40     : m_data(WTFMove(data))
41     , m_channelId(channelId)
42 {
43 }
44
45 // static
46 std::unique_ptr<FidoHidInitPacket> FidoHidInitPacket::createFromSerializedData(const Vector<uint8_t>& serialized, size_t* remainingSize)
47 {
48     if (!remainingSize || serialized.size() != kHidPacketSize)
49         return nullptr;
50
51     size_t index = 0;
52     auto channelId = (serialized[index++] & 0xff) << 24;
53     channelId |= (serialized[index++] & 0xff) << 16;
54     channelId |= (serialized[index++] & 0xff) << 8;
55     channelId |= serialized[index++] & 0xff;
56
57     auto command = static_cast<FidoHidDeviceCommand>(serialized[index++] & 0x7f);
58     if (!isFidoHidDeviceCommand(command))
59         return nullptr;
60
61     uint16_t payloadSize = serialized[index++] << 8;
62     payloadSize |= serialized[index++];
63
64     // Check to see if payload is less than maximum size and padded with 0s.
65     uint16_t dataSize = std::min(payloadSize, static_cast<uint16_t>(kHidPacketSize - index));
66
67     // Update remaining size to determine the payload size of follow on packets.
68     *remainingSize = payloadSize - dataSize;
69
70     auto data = Vector<uint8_t>();
71     data.append(serialized.begin() + index, dataSize);
72
73     return std::make_unique<FidoHidInitPacket>(channelId, command, WTFMove(data), payloadSize);
74 }
75
76 // U2F Initialization packet is defined as:
77 // Offset Length
78 // 0      4       Channel ID
79 // 4      1       Command ID
80 // 5      1       High order packet payload size
81 // 6      1       Low order packet payload size
82 // 7      (s-7)   Payload data
83 FidoHidInitPacket::FidoHidInitPacket(uint32_t channelId, FidoHidDeviceCommand cmd, Vector<uint8_t>&& data, uint16_t payloadLength)
84     : FidoHidPacket(WTFMove(data), channelId)
85     , m_command(cmd)
86     , m_payloadLength(payloadLength)
87 {
88 }
89
90 Vector<uint8_t> FidoHidInitPacket::getSerializedData() const
91 {
92     Vector<uint8_t> serialized;
93     serialized.reserveInitialCapacity(kHidPacketSize);
94     serialized.append((m_channelId >> 24) & 0xff);
95     serialized.append((m_channelId >> 16) & 0xff);
96     serialized.append((m_channelId >> 8) & 0xff);
97     serialized.append(m_channelId & 0xff);
98     serialized.append(static_cast<uint8_t>(m_command) | 0x80);
99     serialized.append((m_payloadLength >> 8) & 0xff);
100     serialized.append(m_payloadLength & 0xff);
101     serialized.append(m_data.begin(), m_data.size());
102     serialized.grow(kHidPacketSize);
103
104     return serialized;
105 }
106
107 // static
108 std::unique_ptr<FidoHidContinuationPacket> FidoHidContinuationPacket::createFromSerializedData(const Vector<uint8_t>& serialized, size_t* remainingSize)
109 {
110     if (!remainingSize || serialized.size() != kHidPacketSize)
111         return nullptr;
112
113     size_t index = 0;
114     auto channelId = (serialized[index++] & 0xff) << 24;
115     channelId |= (serialized[index++] & 0xff) << 16;
116     channelId |= (serialized[index++] & 0xff) << 8;
117     channelId |= serialized[index++] & 0xff;
118     auto sequence = serialized[index++];
119
120     // Check to see if packet payload is less than maximum size and padded with 0s.
121     size_t dataSize = std::min(*remainingSize, kHidPacketSize - index);
122     *remainingSize -= dataSize;
123     auto data = Vector<uint8_t>();
124     data.append(serialized.begin() + index, dataSize);
125
126     return std::make_unique<FidoHidContinuationPacket>(channelId, sequence, WTFMove(data));
127 }
128
129 // U2F Continuation packet is defined as:
130 // Offset Length
131 // 0      4       Channel ID
132 // 4      1       Packet sequence 0x00..0x7f
133 // 5      (s-5)   Payload data
134 FidoHidContinuationPacket::FidoHidContinuationPacket(const uint32_t channelId, const uint8_t sequence, Vector<uint8_t>&& data)
135     : FidoHidPacket(WTFMove(data), channelId)
136     , m_sequence(sequence)
137 {
138 }
139
140 Vector<uint8_t> FidoHidContinuationPacket::getSerializedData() const
141 {
142     Vector<uint8_t> serialized;
143     serialized.reserveInitialCapacity(kHidPacketSize);
144     serialized.append((m_channelId >> 24) & 0xff);
145     serialized.append((m_channelId >> 16) & 0xff);
146     serialized.append((m_channelId >> 8) & 0xff);
147     serialized.append(m_channelId & 0xff);
148     serialized.append(m_sequence);
149     serialized.append(m_data.begin(), m_data.size());
150     serialized.grow(kHidPacketSize);
151
152     return serialized;
153 }
154
155 } // namespace fido
156
157 #endif // ENABLE(WEB_AUTHN)