xref: /aosp_15_r20/external/cronet/base/unguessable_token.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 The Chromium Authors
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 BASE_UNGUESSABLE_TOKEN_H_
6 #define BASE_UNGUESSABLE_TOKEN_H_
7 
8 #include <stdint.h>
9 #include <string.h>
10 #include <compare>
11 #include <iosfwd>
12 #include <tuple>
13 
14 #include "base/base_export.h"
15 #include "base/check.h"
16 #include "base/containers/span.h"
17 #include "base/strings/string_piece.h"
18 #include "base/token.h"
19 
20 namespace base {
21 
22 struct UnguessableTokenHash;
23 
24 // UnguessableToken is, like Token, a randomly chosen 128-bit value. Unlike
25 // Token, a new UnguessableToken is always generated at runtime from a
26 // cryptographically strong random source (or copied or serialized and
27 // deserialized from another such UnguessableToken). Also unlike Token, the ==
28 // and != operators are constant time. It can be used as part of a larger
29 // aggregate type, or as an ID in and of itself.
30 //
31 // An UnguessableToken is a strong *bearer token*. Bearer tokens are like HTTP
32 // cookies: if a caller has the token, the callee thereby considers the caller
33 // authorized to request the operation the callee performs.
34 //
35 // UnguessableToken can be used when the resource associated with the ID needs
36 // to be protected against manipulation by other untrusted agents in the system,
37 // and there is no other convenient way to verify the authority of the agent to
38 // do so (because the resource is part of a table shared across processes, for
39 // instance). In such a scheme, knowledge of the token value in and of itself is
40 // sufficient proof of authority to carry out an operation on the associated
41 // resource.
42 //
43 // Use Create() for creating new UnguessableTokens.
44 //
45 // NOTE: It is illegal to send empty UnguessableTokens across processes, and
46 // sending/receiving empty tokens should be treated as a security issue. If
47 // there is a valid scenario for sending "no token" across processes, use
48 // std::optional instead of an empty token.
49 
50 class BASE_EXPORT UnguessableToken {
51  public:
52   // Create a unique UnguessableToken. It's guaranteed to be nonempty.
53   static UnguessableToken Create();
54 
55   // Returns a reference to a global null UnguessableToken. This should only be
56   // used for functions that need to return a reference to an UnguessableToken,
57   // and should not be used as a general-purpose substitute for invoking the
58   // default constructor.
59   static const UnguessableToken& Null();
60 
61   // Return an UnguessableToken built from the high/low bytes provided.
62   // It should only be used in deserialization scenarios.
63   //
64   // NOTE: If the returned `std::optional` does not have a value, it means that
65   // `high` and `low` correspond to an `UnguesssableToken` that was never
66   // initialized via Create(). This is a security issue, and should be handled.
67   static std::optional<UnguessableToken> Deserialize(uint64_t high,
68                                                      uint64_t low);
69 
70   // Returns an `UnguessableToken` built from its string representation. It
71   // should only be used in deserialization scenarios.
72   //
73   // NOTE: If the returned `std::optional` does not have a value, it means that
74   // the given string does not represent a valid serialized `UnguessableToken`.
75   // This should be handled as a security issue.
76   static std::optional<UnguessableToken> DeserializeFromString(
77       StringPiece string_representation);
78 
79   // Creates an empty UnguessableToken.
80   // Assign to it with Create() before using it.
81   constexpr UnguessableToken() = default;
82 
83   constexpr UnguessableToken(const UnguessableToken&) = default;
84   constexpr UnguessableToken& operator=(const UnguessableToken&) = default;
85   constexpr UnguessableToken(UnguessableToken&&) noexcept = default;
86   constexpr UnguessableToken& operator=(UnguessableToken&&) = default;
87 
88   // NOTE: Serializing an empty UnguessableToken is an illegal operation.
GetHighForSerialization()89   uint64_t GetHighForSerialization() const {
90     DCHECK(!is_empty());
91     return token_.high();
92   }
93 
94   // NOTE: Serializing an empty UnguessableToken is an illegal operation.
GetLowForSerialization()95   uint64_t GetLowForSerialization() const {
96     DCHECK(!is_empty());
97     return token_.low();
98   }
99 
is_empty()100   constexpr bool is_empty() const { return token_.is_zero(); }
101 
102   // Hex representation of the unguessable token.
ToString()103   std::string ToString() const { return token_.ToString(); }
104 
105   explicit constexpr operator bool() const { return !is_empty(); }
106 
AsBytes()107   span<const uint8_t, 16> AsBytes() const { return token_.AsBytes(); }
108 
109   friend constexpr auto operator<=>(const UnguessableToken& lhs,
110                                     const UnguessableToken& rhs) = default;
111 
112   // operator== uses constant-time comparison for security where available.
113   friend BASE_EXPORT bool operator==(const UnguessableToken& lhs,
114                                      const UnguessableToken& rhs);
115 
116 #if defined(UNIT_TEST)
CreateForTesting(uint64_t high,uint64_t low)117   static UnguessableToken CreateForTesting(uint64_t high, uint64_t low) {
118     std::optional<UnguessableToken> token = Deserialize(high, low);
119     DCHECK(token.has_value());
120     return token.value();
121   }
122 #endif
123 
124  private:
125   friend struct UnguessableTokenHash;
126   explicit UnguessableToken(const Token& token);
127 
128   base::Token token_;
129 };
130 
131 BASE_EXPORT bool operator==(const UnguessableToken& lhs,
132                             const UnguessableToken& rhs);
133 
134 BASE_EXPORT std::ostream& operator<<(std::ostream& out,
135                                      const UnguessableToken& token);
136 
137 // For use in std::unordered_map.
138 struct UnguessableTokenHash {
operatorUnguessableTokenHash139   size_t operator()(const base::UnguessableToken& token) const {
140     DCHECK(token);
141     return TokenHash()(token.token_);
142   }
143 };
144 
145 }  // namespace base
146 
147 #endif  // BASE_UNGUESSABLE_TOKEN_H_
148