blob: 38db54ebdd9e79afc55c49432e1bf3075d2cbe6c [file] [log] [blame]
Kim Paulhamus6efcf4952017-09-14 22:46:271// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_VALUES_H_
6#define CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_VALUES_H_
7
Jun Choi06ae32d2017-12-21 18:52:398#include <stdint.h>
Kim Paulhamus6efcf4952017-09-14 22:46:279#include <string>
Adam Langley68672fd2017-10-17 19:35:2710#include <tuple>
Kim Paulhamus6efcf4952017-09-14 22:46:2711#include <vector>
12
13#include "base/containers/flat_map.h"
14#include "base/macros.h"
Adam Langleydf763d792017-11-28 19:20:1515#include "base/strings/string_piece.h"
Kim Paulhamus6efcf4952017-09-14 22:46:2716#include "content/common/content_export.h"
17
18namespace content {
19
20// A class for Concise Binary Object Representation (CBOR) values.
21// This does not support:
Kim Paulhamus6efcf4952017-09-14 22:46:2722// * Floating-point numbers.
23// * Indefinite-length encodings.
24class CONTENT_EXPORT CBORValue {
25 public:
Adam Langley68672fd2017-10-17 19:35:2726 struct CTAPLess {
27 // Comparison predicate to order keys in a dictionary as required by the
28 // Client-to-Authenticator Protocol (CTAP) spec 2.0.
29 //
30 // The sort order defined in CTAP is:
31 // • If the major types are different, the one with the lower value in
Jun Choi98a59e462017-12-14 23:04:0932 // numerical order sorts earlier.
Adam Langley68672fd2017-10-17 19:35:2733 // • If two keys have different lengths, the shorter one sorts earlier.
34 // • If two keys have the same length, the one with the lower value in
35 // (byte-wise) lexical order sorts earlier.
36 //
37 // See section 6 of https://fidoalliance.org/specs/fido-v2.0-rd-20170927/
Adam Langleydf763d792017-11-28 19:20:1538 // fido-client-to-authenticator-protocol-v2.0-rd-20170927.html.
39 //
Jun Choi98a59e462017-12-14 23:04:0940 // THE CTAP SORT ORDER IMPLEMENTED HERE DIFFERS FROM THE CANONICAL CBOR
41 // ORDER defined in https://tools.ietf.org/html/rfc7049#section-3.9, in that
42 // the latter sorts purely by serialised key and doesn't specify that major
43 // types are compared first. Thus the shortest key sorts first by the RFC
44 // rules (irrespective of the major type), but may not by CTAP rules.
45 bool operator()(const CBORValue& a, const CBORValue& b) const {
Jun Choi06ae32d2017-12-21 18:52:3946 DCHECK((a.is_integer() || a.is_string()) &&
47 (b.is_integer() || b.is_string()));
Jun Choi98a59e462017-12-14 23:04:0948 if (a.type() != b.type())
49 return a.type() < b.type();
50 switch (a.type()) {
51 case Type::UNSIGNED:
Jun Choi06ae32d2017-12-21 18:52:3952 return a.GetInteger() < b.GetInteger();
53 case Type::NEGATIVE:
54 return a.GetInteger() > b.GetInteger();
Jun Choi98a59e462017-12-14 23:04:0955 case Type::STRING: {
56 const auto& a_str = a.GetString();
57 const size_t a_length = a_str.size();
58 const auto& b_str = b.GetString();
59 const size_t b_length = b_str.size();
60 return std::tie(a_length, a_str) < std::tie(b_length, b_str);
61 }
62 default:
63 break;
64 }
65
66 NOTREACHED();
67 return false;
Adam Langley68672fd2017-10-17 19:35:2768 }
69
Adam Langley68672fd2017-10-17 19:35:2770 using is_transparent = void;
71 };
72
Kim Paulhamus6efcf4952017-09-14 22:46:2773 using BinaryValue = std::vector<uint8_t>;
74 using ArrayValue = std::vector<CBORValue>;
Jun Choi98a59e462017-12-14 23:04:0975 using MapValue = base::flat_map<CBORValue, CBORValue, CTAPLess>;
Kim Paulhamus6efcf4952017-09-14 22:46:2776
77 enum class Type {
Jun Choi6d30c4a2017-12-09 01:10:3278 UNSIGNED = 0,
Jun Choi06ae32d2017-12-21 18:52:3979 NEGATIVE = 1,
Jun Choi6d30c4a2017-12-09 01:10:3280 BYTE_STRING = 2,
81 STRING = 3,
82 ARRAY = 4,
83 MAP = 5,
Jun Choi07540c62017-12-21 02:51:4384 SIMPLE_VALUE = 7,
Jun Choi6d30c4a2017-12-09 01:10:3285 NONE = -1,
Kim Paulhamus6efcf4952017-09-14 22:46:2786 };
87
Jun Choi07540c62017-12-21 02:51:4388 enum class SimpleValue {
89 FALSE_VALUE = 20,
90 TRUE_VALUE = 21,
91 NULL_VALUE = 22,
92 UNDEFINED = 23,
93 };
94
Kim Paulhamus6efcf4952017-09-14 22:46:2795 CBORValue(CBORValue&& that) noexcept;
96 CBORValue() noexcept; // A NONE value.
97
98 explicit CBORValue(Type type);
Jun Choi06ae32d2017-12-21 18:52:3999 explicit CBORValue(int integer_value);
100 explicit CBORValue(int64_t integer_value);
101 explicit CBORValue(uint64_t integer_value) = delete;
Kim Paulhamus6efcf4952017-09-14 22:46:27102
103 explicit CBORValue(const BinaryValue& in_bytes);
104 explicit CBORValue(BinaryValue&& in_bytes) noexcept;
105
106 explicit CBORValue(const char* in_string);
107 explicit CBORValue(std::string&& in_string) noexcept;
108 explicit CBORValue(base::StringPiece in_string);
109
110 explicit CBORValue(const ArrayValue& in_array);
111 explicit CBORValue(ArrayValue&& in_array) noexcept;
112
113 explicit CBORValue(const MapValue& in_map);
114 explicit CBORValue(MapValue&& in_map) noexcept;
115
Jun Choi07540c62017-12-21 02:51:43116 explicit CBORValue(SimpleValue in_simple);
117
Kim Paulhamus6efcf4952017-09-14 22:46:27118 CBORValue& operator=(CBORValue&& that) noexcept;
119
120 ~CBORValue();
121
122 // CBORValue's copy constructor and copy assignment operator are deleted.
123 // Use this to obtain a deep copy explicitly.
124 CBORValue Clone() const;
125
126 // Returns the type of the value stored by the current Value object.
127 Type type() const { return type_; }
128
129 // Returns true if the current object represents a given type.
130 bool is_type(Type type) const { return type == type_; }
131 bool is_none() const { return type() == Type::NONE; }
132 bool is_unsigned() const { return type() == Type::UNSIGNED; }
Jun Choi06ae32d2017-12-21 18:52:39133 bool is_negative() const { return type() == Type::NEGATIVE; }
134 bool is_integer() const { return is_unsigned() || is_negative(); }
Jun Choi6d30c4a2017-12-09 01:10:32135 bool is_bytestring() const { return type() == Type::BYTE_STRING; }
Kim Paulhamus6efcf4952017-09-14 22:46:27136 bool is_string() const { return type() == Type::STRING; }
137 bool is_array() const { return type() == Type::ARRAY; }
138 bool is_map() const { return type() == Type::MAP; }
Jun Choi07540c62017-12-21 02:51:43139 bool is_simple() const { return type() == Type::SIMPLE_VALUE; }
Kim Paulhamus6efcf4952017-09-14 22:46:27140
141 // These will all fatally assert if the type doesn't match.
Jun Choi07540c62017-12-21 02:51:43142 SimpleValue GetSimpleValue() const;
Jun Choi06ae32d2017-12-21 18:52:39143 const int64_t& GetInteger() const;
144 const int64_t& GetUnsigned() const;
145 const int64_t& GetNegative() const;
Kim Paulhamus6efcf4952017-09-14 22:46:27146 const BinaryValue& GetBytestring() const;
Jun Choi47be22c2017-12-14 07:55:16147 // Returned string may contain NUL characters.
Kim Paulhamus6efcf4952017-09-14 22:46:27148 const std::string& GetString() const;
149 const ArrayValue& GetArray() const;
150 const MapValue& GetMap() const;
151
152 private:
153 Type type_;
154
155 union {
Jun Choi07540c62017-12-21 02:51:43156 SimpleValue simple_value_;
Jun Choi06ae32d2017-12-21 18:52:39157 int64_t integer_value_;
Daniel Cheng9eb43fd342017-10-10 21:28:37158 BinaryValue bytestring_value_;
159 std::string string_value_;
160 ArrayValue array_value_;
161 MapValue map_value_;
Kim Paulhamus6efcf4952017-09-14 22:46:27162 };
163
164 void InternalMoveConstructFrom(CBORValue&& that);
165 void InternalCleanup();
166
167 DISALLOW_COPY_AND_ASSIGN(CBORValue);
168};
169} // namespace content
170
Daniel Cheng9eb43fd342017-10-10 21:28:37171#endif // CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_VALUES_H_