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#pragma once
31
32#if ENABLE(WEB_AUTHN)
33
34#include <stdint.h>
35#include <wtf/Noncopyable.h>
36#include <wtf/StdMap.h>
37#include <wtf/Vector.h>
38#include <wtf/text/WTFString.h>
39
40namespace cbor {
41
42// A class for Concise Binary Object Representation (CBOR) values.
43// This does not support:
44// * Floating-point numbers.
45// * Indefinite-length encodings.
46class WEBCORE_EXPORT CBORValue {
47 WTF_MAKE_NONCOPYABLE(CBORValue);
48public:
49 struct CTAPLess {
50 // Comparison predicate to order keys in a dictionary as required by the
51 // Client-to-Authenticator Protocol (CTAP) spec 2.0.
52 //
53 // The sort order defined in CTAP is:
54 // * If the major types are different, the one with the lower value in
55 // numerical order sorts earlier.
56 // * If two keys have different lengths, the shorter one sorts earlier.
57 // * If two keys have the same length, the one with the lower value in
58 // (byte-wise) lexical order sorts earlier.
59 //
60 // See section 6 of https://fidoalliance.org/specs/fido-v2.0-rd-20170927/
61 // fido-client-to-authenticator-protocol-v2.0-rd-20170927.html.
62 //
63 // THE CTAP SORT ORDER IMPLEMENTED HERE DIFFERS FROM THE CANONICAL CBOR
64 // ORDER defined in https://tools.ietf.org/html/rfc7049#section-3.9, in that
65 // the latter sorts purely by serialised key and doesn't specify that major
66 // types are compared first. Thus the shortest key sorts first by the RFC
67 // rules (irrespective of the major type), but may not by CTAP rules.
68 bool operator()(const CBORValue& a, const CBORValue& b) const
69 {
70 ASSERT((a.isInteger() || a.isString()) && (b.isInteger() || b.isString()));
71 if (a.type() != b.type())
72 return a.type() < b.type();
73 switch (a.type()) {
74 case Type::Unsigned:
75 return a.getInteger() < b.getInteger();
76 case Type::Negative:
77 return a.getInteger() > b.getInteger();
78 case Type::String: {
79 const auto& aStr = a.getString();
80 const size_t aLength = aStr.length();
81 const auto& bStr = b.getString();
82 const size_t bLength = bStr.length();
83
84 if (aLength != bLength)
85 return aLength < bLength;
86 return WTF::codePointCompareLessThan(aStr, bStr);
87 }
88 default:
89 break;
90 }
91
92 ASSERT_NOT_REACHED();
93 return false;
94 }
95 };
96
97 using BinaryValue = Vector<uint8_t>;
98 using ArrayValue = Vector<CBORValue>;
99 using MapValue = StdMap<CBORValue, CBORValue, CTAPLess>;
100
101 enum class Type {
102 Unsigned = 0,
103 Negative = 1,
104 ByteString = 2,
105 String = 3,
106 Array = 4,
107 Map = 5,
108 SimpleValue = 7,
109 None = -1,
110 };
111
112 enum class SimpleValue {
113 FalseValue = 20,
114 TrueValue = 21,
115 NullValue = 22,
116 Undefined = 23,
117 };
118
119 CBORValue(CBORValue&& that);
120 CBORValue(); // A NONE value.
121
122 explicit CBORValue(Type);
123 explicit CBORValue(int);
124 explicit CBORValue(int64_t);
125 explicit CBORValue(uint64_t) = delete;
126
127 explicit CBORValue(const BinaryValue&);
128 explicit CBORValue(BinaryValue&&);
129
130 explicit CBORValue(const char*);
131 explicit CBORValue(String&&);
132 explicit CBORValue(const String&);
133
134 explicit CBORValue(const ArrayValue&);
135 explicit CBORValue(ArrayValue&&);
136
137 explicit CBORValue(const MapValue&);
138 explicit CBORValue(MapValue&&);
139
140 explicit CBORValue(SimpleValue);
141 explicit CBORValue(bool);
142
143 CBORValue& operator=(CBORValue&&);
144
145 ~CBORValue();
146
147 // CBORValue's copy constructor and copy assignment operator are deleted.
148 // Use this to obtain a deep copy explicitly.
149 CBORValue clone() const;
150
151 // Returns the type of the value stored by the current Value object.
152 Type type() const { return m_type; }
153
154 // Returns true if the current object represents a given type.
155 bool isType(Type type) const { return type == m_type; }
156 bool isNone() const { return type() == Type::None; }
157 bool isUnsigned() const { return type() == Type::Unsigned; }
158 bool isNegative() const { return type() == Type::Negative; }
159 bool isInteger() const { return isUnsigned() || isNegative(); }
160 bool isByteString() const { return type() == Type::ByteString; }
161 bool isString() const { return type() == Type::String; }
162 bool isArray() const { return type() == Type::Array; }
163 bool isMap() const { return type() == Type::Map; }
164 bool isSimple() const { return type() == Type::SimpleValue; }
165 bool isBool() const { return isSimple() && (m_simpleValue == SimpleValue::TrueValue || m_simpleValue == SimpleValue::FalseValue); }
166
167 // These will all fatally assert if the type doesn't match.
168 SimpleValue getSimpleValue() const;
169 bool getBool() const;
170 const int64_t& getInteger() const;
171 const int64_t& getUnsigned() const;
172 const int64_t& getNegative() const;
173 const BinaryValue& getByteString() const;
174 // Returned string may contain NUL characters.
175 const String& getString() const;
176 const ArrayValue& getArray() const;
177 const MapValue& getMap() const;
178
179private:
180 Type m_type;
181
182 union {
183 SimpleValue m_simpleValue;
184 int64_t m_integerValue;
185 BinaryValue m_byteStringValue;
186 String m_stringValue;
187 ArrayValue m_arrayValue;
188 MapValue m_mapValue;
189 };
190
191 void internalMoveConstructFrom(CBORValue&&);
192 void internalCleanup();
193};
194
195} // namespace cbor
196
197#endif // ENABLE(WEB_AUTHN)
198