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