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 | |
74 | namespace cbor { |
75 | |
76 | class CBORWriter { |
77 | WTF_MAKE_NONCOPYABLE(CBORWriter); |
78 | public: |
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 | |
92 | private: |
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 | |