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