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 "CBORValue.h"
35#include <stddef.h>
36
37// A basic Concise Binary Object Representation (CBOR) encoder as defined by
38// https://tools.ietf.org/html/rfc7049. This is a generic encoder that supplies
39// canonical, well-formed CBOR values but does not guarantee their validity
40// (see https://tools.ietf.org/html/rfc7049#section-3.2).
41// Supported:
42// * Major types:
43// * 0: Unsigned integers, up to INT64_MAX.
44// * 1: Negative integers, to INT64_MIN.
45// * 2: Byte strings.
46// * 3: UTF-8 strings.
47// * 4: Arrays, with the number of elements known at the start.
48// * 5: Maps, with the number of elements known at the start
49// of the container.
50// * 7: Simple values.
51//
52// Unsupported:
53// * Floating-point numbers.
54// * Indefinite-length encodings.
55// * Parsing.
56//
57// Requirements for canonical CBOR as suggested by RFC 7049 are:
58// 1) All major data types for the CBOR values must be as short as possible.
59// * Unsigned integer between 0 to 23 must be expressed in same byte as
60// the major type.
61// * 24 to 255 must be expressed only with an additional uint8_t.
62// * 256 to 65535 must be expressed only with an additional uint16_t.
63// * 65536 to 4294967295 must be expressed only with an additional
64// uint32_t. * The rules for expression of length in major types
65// 2 to 5 follow the above rule for integers.
66// 2) Keys in every map must be sorted (first by major type, then by key
67// length, then by value in byte-wise lexical order).
68// 3) Indefinite length items must be converted to definite length items.
69// 4) All maps must not have duplicate keys.
70//
71// Current implementation of CBORWriter encoder meets all the requirements of
72// canonical CBOR.
73
74namespace cbor {
75
76class CBORWriter {
77 WTF_MAKE_NONCOPYABLE(CBORWriter);
78public:
79 // Default that should be sufficiently large for most use cases.
80 static constexpr size_t kDefaultMaxNestingDepth = 16;
81
82 ~CBORWriter();
83
84 // Returns the CBOR byte string representation of |node|, unless its nesting
85 // depth is greater than |max_nesting_depth|, in which case an empty optional
86 // value is returned. The nesting depth of |node| is defined as the number of
87 // arrays/maps that has to be traversed to reach the most nested CBORValue
88 // contained in |node|. Primitive values and empty containers have nesting
89 // depths of 0.
90 WEBCORE_EXPORT static Optional<Vector<uint8_t>> write(const CBORValue&, size_t maxNestingLevel = kDefaultMaxNestingDepth);
91
92private:
93 explicit CBORWriter(Vector<uint8_t>*);
94
95 // Called recursively to build the CBOR bytestring. When completed,
96 // |m_encodedCBOR| will contain the CBOR.
97 bool encodeCBOR(const CBORValue&, int maxNestingLevel);
98
99 // Encodes the type and size of the data being added.
100 void startItem(CBORValue::Type, uint64_t size);
101
102 // Encodes the additional information for the data.
103 void setAdditionalInformation(uint8_t);
104
105 // Encodes an unsigned integer value. This is used to both write
106 // unsigned integers and to encode the lengths of other major types.
107 void setUint(uint64_t value);
108
109 // Get the number of bytes needed to store the unsigned integer.
110 size_t getNumUintBytes(uint64_t value);
111
112 // Holds the encoded CBOR data.
113 Vector<uint8_t>* m_encodedCBOR;
114};
115
116} // namespace cbor
117
118#endif // ENABLE(WEB_AUTHN)
119