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