blob: f79efd486f2cf1721b9c4d7c534743a63525795e [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Copyright (C) 2018-2021 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 <stdint.h>
#include <wtf/Noncopyable.h>
#include <wtf/StdMap.h>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
class BufferSource;
}
namespace cbor {
// A class for Concise Binary Object Representation (CBOR) values.
// This does not support:
// * Floating-point numbers.
// * Indefinite-length encodings.
class WEBCORE_EXPORT CBORValue {
WTF_MAKE_NONCOPYABLE(CBORValue);
public:
struct CTAPLess {
// Comparison predicate to order keys in a dictionary as required by the
// Client-to-Authenticator Protocol (CTAP) spec 2.0.
//
// The sort order defined in CTAP is:
// * If the major types are different, the one with the lower value in
// numerical order sorts earlier.
// * If two keys have different lengths, the shorter one sorts earlier.
// * If two keys have the same length, the one with the lower value in
// (byte-wise) lexical order sorts earlier.
//
// See section 6 of https://fidoalliance.org/specs/fido-v2.0-rd-20170927/
// fido-client-to-authenticator-protocol-v2.0-rd-20170927.html.
//
// THE CTAP SORT ORDER IMPLEMENTED HERE DIFFERS FROM THE CANONICAL CBOR
// ORDER defined in https://tools.ietf.org/html/rfc7049#section-3.9, in that
// the latter sorts purely by serialised key and doesn't specify that major
// types are compared first. Thus the shortest key sorts first by the RFC
// rules (irrespective of the major type), but may not by CTAP rules.
bool operator()(const CBORValue& a, const CBORValue& b) const
{
ASSERT((a.isInteger() || a.isString()) && (b.isInteger() || b.isString()));
if (a.type() != b.type())
return a.type() < b.type();
switch (a.type()) {
case Type::Unsigned:
return a.getInteger() < b.getInteger();
case Type::Negative:
return a.getInteger() > b.getInteger();
case Type::String: {
const auto& aStr = a.getString();
const size_t aLength = aStr.length();
const auto& bStr = b.getString();
const size_t bLength = bStr.length();
if (aLength != bLength)
return aLength < bLength;
return WTF::codePointCompareLessThan(aStr, bStr);
}
default:
break;
}
ASSERT_NOT_REACHED();
return false;
}
};
using BinaryValue = Vector<uint8_t>;
using ArrayValue = Vector<CBORValue>;
using MapValue = StdMap<CBORValue, CBORValue, CTAPLess>;
enum class Type {
Unsigned = 0,
Negative = 1,
ByteString = 2,
String = 3,
Array = 4,
Map = 5,
SimpleValue = 7,
None = -1,
};
enum class SimpleValue {
FalseValue = 20,
TrueValue = 21,
NullValue = 22,
Undefined = 23,
};
CBORValue(CBORValue&& that);
CBORValue(); // A NONE value.
explicit CBORValue(Type);
explicit CBORValue(int);
explicit CBORValue(int64_t);
explicit CBORValue(uint64_t) = delete;
explicit CBORValue(const BinaryValue&);
explicit CBORValue(BinaryValue&&);
explicit CBORValue(const WebCore::BufferSource&);
explicit CBORValue(const char*);
explicit CBORValue(String&&);
explicit CBORValue(const String&);
explicit CBORValue(const ArrayValue&);
explicit CBORValue(ArrayValue&&);
explicit CBORValue(const MapValue&);
explicit CBORValue(MapValue&&);
explicit CBORValue(SimpleValue);
explicit CBORValue(bool);
CBORValue& operator=(CBORValue&&);
~CBORValue();
// CBORValue's copy constructor and copy assignment operator are deleted.
// Use this to obtain a deep copy explicitly.
CBORValue clone() const;
// Returns the type of the value stored by the current Value object.
Type type() const { return m_type; }
// Returns true if the current object represents a given type.
bool isType(Type type) const { return type == m_type; }
bool isNone() const { return type() == Type::None; }
bool isUnsigned() const { return type() == Type::Unsigned; }
bool isNegative() const { return type() == Type::Negative; }
bool isInteger() const { return isUnsigned() || isNegative(); }
bool isByteString() const { return type() == Type::ByteString; }
bool isString() const { return type() == Type::String; }
bool isArray() const { return type() == Type::Array; }
bool isMap() const { return type() == Type::Map; }
bool isSimple() const { return type() == Type::SimpleValue; }
bool isBool() const { return isSimple() && (m_simpleValue == SimpleValue::TrueValue || m_simpleValue == SimpleValue::FalseValue); }
// FIXME(183535): Considering adding && getter for better performance.
// These will all fatally assert if the type doesn't match.
SimpleValue getSimpleValue() const;
bool getBool() const;
const int64_t& getInteger() const;
const int64_t& getUnsigned() const;
const int64_t& getNegative() const;
const BinaryValue& getByteString() const;
// Returned string may contain NUL characters.
const String& getString() const;
const ArrayValue& getArray() const;
const MapValue& getMap() const;
private:
Type m_type;
union {
SimpleValue m_simpleValue;
int64_t m_integerValue;
BinaryValue m_byteStringValue;
String m_stringValue;
ArrayValue m_arrayValue;
MapValue m_mapValue;
};
void internalMoveConstructFrom(CBORValue&&);
void internalCleanup();
};
} // namespace cbor
#endif // ENABLE(WEB_AUTHN)