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