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) |
158 | |