device/fido: handle user-info truncation.

CTAP2 authenticators are permitted to truncate |name| and |displayName|
fields at 64 bytes, and CTAP2 Yubikeys actually do so. However, this
truncation is done without any reference to the UTF-8 structure thus can
truncate in the middle of a multi-byte code-point. This makes future
responses from the authenticator potentially invalid CBOR because the
strings within are invalid UTF-8.

This change adds a facility to components/cbor to allow users of the
parser to indicate that invalid UTF-8 (except in map keys) should be
returned as Values of type |INVALID_UTF8|.

This change also uses this facility when processing CTAP2 GetAssertion
responses to allow precisely the |name| and |displayName| fields to be
truncated at (or after) 64 bytes. Any partial, multi-byte sequence at
the end of the invalid UTF-8 is dropped.

Bug: 941120
Change-Id: I1742128ee1e689fe400083404f17efc8afd55a97
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1573091
Commit-Queue: Adam Langley <[email protected]>
Reviewed-by: Chris Palmer <[email protected]>
Reviewed-by: Balazs Engedy <[email protected]>
Auto-Submit: Adam Langley <[email protected]>
Cr-Commit-Position: refs/heads/master@{#652977}
diff --git a/components/cbor/values.h b/components/cbor/values.h
index ed9aae2..c6c5ee61 100644
--- a/components/cbor/values.h
+++ b/components/cbor/values.h
@@ -94,6 +94,7 @@
     TAG = 6,
     SIMPLE_VALUE = 7,
     NONE = -1,
+    INVALID_UTF8 = -2,
   };
 
   enum class SimpleValue {
@@ -142,6 +143,7 @@
   // Returns true if the current object represents a given type.
   bool is_type(Type type) const { return type == type_; }
   bool is_none() const { return type() == Type::NONE; }
+  bool is_invalid_utf8() const { return type() == Type::INVALID_UTF8; }
   bool is_simple() const { return type() == Type::SIMPLE_VALUE; }
   bool is_bool() const {
     return is_simple() && (simple_value_ == SimpleValue::TRUE_VALUE ||
@@ -167,8 +169,14 @@
   const std::string& GetString() const;
   const ArrayValue& GetArray() const;
   const MapValue& GetMap() const;
+  const BinaryValue& GetInvalidUTF8() const;
 
  private:
+  friend class Reader;
+  // This constructor allows INVALID_UTF8 values to be created, which only
+  // |Reader| may do.
+  Value(base::span<const uint8_t> in_bytes, Type type);
+
   Type type_;
 
   union {