Support CBOR encoding and decoding of negative integers

Added support for major type 1 for CBORValue, CBORReader, and
CBORWriter, and reduced the accepted range of major type 0 to
what fits in an int64_t. While the CBOR major types 0 and 1
together can represent integers in the range [-2^64, 2^64-1], to
reduce the C++ interface complexity we now represent them both in
an int64_t, with the range [-2^63, 2^63-1].

Bug: 786217
Change-Id: Ifee69efcddecea104532b99176d705b3d2801f41
Reviewed-on: https://chromium-review.googlesource.com/777807
Commit-Queue: Jun Choi <[email protected]>
Reviewed-by: Balazs Engedy <[email protected]>
Reviewed-by: Jeffrey Yasskin <[email protected]>
Cr-Commit-Position: refs/heads/master@{#525809}
diff --git a/content/browser/webauth/cbor/cbor_values.h b/content/browser/webauth/cbor/cbor_values.h
index 9b35fda..38db54e 100644
--- a/content/browser/webauth/cbor/cbor_values.h
+++ b/content/browser/webauth/cbor/cbor_values.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_VALUES_H_
 #define CONTENT_BROWSER_WEBAUTH_CBOR_CBOR_VALUES_H_
 
+#include <stdint.h>
 #include <string>
 #include <tuple>
 #include <vector>
@@ -18,7 +19,6 @@
 
 // A class for Concise Binary Object Representation (CBOR) values.
 // This does not support:
-//  * Negative integers.
 //  * Floating-point numbers.
 //  * Indefinite-length encodings.
 class CONTENT_EXPORT CBORValue {
@@ -43,13 +43,15 @@
     // 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 {
-      DCHECK((a.is_unsigned() || a.is_string()) &&
-             (b.is_unsigned() || b.is_string()));
+      DCHECK((a.is_integer() || a.is_string()) &&
+             (b.is_integer() || b.is_string()));
       if (a.type() != b.type())
         return a.type() < b.type();
       switch (a.type()) {
         case Type::UNSIGNED:
-          return a.GetUnsigned() < b.GetUnsigned();
+          return a.GetInteger() < b.GetInteger();
+        case Type::NEGATIVE:
+          return a.GetInteger() > b.GetInteger();
         case Type::STRING: {
           const auto& a_str = a.GetString();
           const size_t a_length = a_str.size();
@@ -74,6 +76,7 @@
 
   enum class Type {
     UNSIGNED = 0,
+    NEGATIVE = 1,
     BYTE_STRING = 2,
     STRING = 3,
     ARRAY = 4,
@@ -93,7 +96,9 @@
   CBORValue() noexcept;  // A NONE value.
 
   explicit CBORValue(Type type);
-  explicit CBORValue(uint64_t in_unsigned);
+  explicit CBORValue(int integer_value);
+  explicit CBORValue(int64_t integer_value);
+  explicit CBORValue(uint64_t integer_value) = delete;
 
   explicit CBORValue(const BinaryValue& in_bytes);
   explicit CBORValue(BinaryValue&& in_bytes) noexcept;
@@ -125,6 +130,8 @@
   bool is_type(Type type) const { return type == type_; }
   bool is_none() const { return type() == Type::NONE; }
   bool is_unsigned() const { return type() == Type::UNSIGNED; }
+  bool is_negative() const { return type() == Type::NEGATIVE; }
+  bool is_integer() const { return is_unsigned() || is_negative(); }
   bool is_bytestring() const { return type() == Type::BYTE_STRING; }
   bool is_string() const { return type() == Type::STRING; }
   bool is_array() const { return type() == Type::ARRAY; }
@@ -132,8 +139,10 @@
   bool is_simple() const { return type() == Type::SIMPLE_VALUE; }
 
   // These will all fatally assert if the type doesn't match.
-  const uint64_t& GetUnsigned() const;
   SimpleValue GetSimpleValue() 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 std::string& GetString() const;
@@ -145,7 +154,7 @@
 
   union {
     SimpleValue simple_value_;
-    uint64_t unsigned_value_;
+    int64_t integer_value_;
     BinaryValue bytestring_value_;
     std::string string_value_;
     ArrayValue array_value_;