1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148

base / unguessable_token.h [blame]

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_UNGUESSABLE_TOKEN_H_
#define BASE_UNGUESSABLE_TOKEN_H_

#include <stdint.h>
#include <string.h>

#include <compare>
#include <iosfwd>
#include <string_view>
#include <tuple>

#include "base/base_export.h"
#include "base/check.h"
#include "base/containers/span.h"
#include "base/token.h"

namespace base {

struct UnguessableTokenHash;

// UnguessableToken is, like Token, a randomly chosen 128-bit value. Unlike
// Token, a new UnguessableToken is always generated at runtime from a
// cryptographically strong random source (or copied or serialized and
// deserialized from another such UnguessableToken). Also unlike Token, the ==
// and != operators are constant time. It can be used as part of a larger
// aggregate type, or as an ID in and of itself.
//
// An UnguessableToken is a strong *bearer token*. Bearer tokens are like HTTP
// cookies: if a caller has the token, the callee thereby considers the caller
// authorized to request the operation the callee performs.
//
// UnguessableToken can be used when the resource associated with the ID needs
// to be protected against manipulation by other untrusted agents in the system,
// and there is no other convenient way to verify the authority of the agent to
// do so (because the resource is part of a table shared across processes, for
// instance). In such a scheme, knowledge of the token value in and of itself is
// sufficient proof of authority to carry out an operation on the associated
// resource.
//
// Use Create() for creating new UnguessableTokens.
//
// NOTE: It is illegal to send empty UnguessableTokens across processes, and
// sending/receiving empty tokens should be treated as a security issue. If
// there is a valid scenario for sending "no token" across processes, use
// std::optional instead of an empty token.

class BASE_EXPORT UnguessableToken {
 public:
  // Create a unique UnguessableToken. It's guaranteed to be nonempty.
  static UnguessableToken Create();

  // Returns a reference to a global null UnguessableToken. This should only be
  // used for functions that need to return a reference to an UnguessableToken,
  // and should not be used as a general-purpose substitute for invoking the
  // default constructor.
  static const UnguessableToken& Null();

  // Return an UnguessableToken built from the high/low bytes provided.
  // It should only be used in deserialization scenarios.
  //
  // NOTE: If the returned `std::optional` does not have a value, it means that
  // `high` and `low` correspond to an `UnguesssableToken` that was never
  // initialized via Create(). This is a security issue, and should be handled.
  static std::optional<UnguessableToken> Deserialize(uint64_t high,
                                                     uint64_t low);

  // Returns an `UnguessableToken` built from its string representation. It
  // should only be used in deserialization scenarios.
  //
  // NOTE: If the returned `std::optional` does not have a value, it means that
  // the given string does not represent a valid serialized `UnguessableToken`.
  // This should be handled as a security issue.
  static std::optional<UnguessableToken> DeserializeFromString(
      std::string_view string_representation);

  // Creates an empty UnguessableToken.
  // Assign to it with Create() before using it.
  constexpr UnguessableToken() = default;

  constexpr UnguessableToken(const UnguessableToken&) = default;
  constexpr UnguessableToken& operator=(const UnguessableToken&) = default;
  constexpr UnguessableToken(UnguessableToken&&) noexcept = default;
  constexpr UnguessableToken& operator=(UnguessableToken&&) = default;

  // NOTE: Serializing an empty UnguessableToken is an illegal operation.
  uint64_t GetHighForSerialization() const {
    DCHECK(!is_empty());
    return token_.high();
  }

  // NOTE: Serializing an empty UnguessableToken is an illegal operation.
  uint64_t GetLowForSerialization() const {
    DCHECK(!is_empty());
    return token_.low();
  }

  constexpr bool is_empty() const { return token_.is_zero(); }

  // Hex representation of the unguessable token.
  std::string ToString() const { return token_.ToString(); }

  explicit constexpr operator bool() const { return !is_empty(); }

  span<const uint8_t, 16> AsBytes() const { return token_.AsBytes(); }

  friend constexpr auto operator<=>(const UnguessableToken& lhs,
                                    const UnguessableToken& rhs) = default;

  // operator== uses constant-time comparison for security where available.
  friend BASE_EXPORT bool operator==(const UnguessableToken& lhs,
                                     const UnguessableToken& rhs);

#if defined(UNIT_TEST)
  static UnguessableToken CreateForTesting(uint64_t high, uint64_t low) {
    std::optional<UnguessableToken> token = Deserialize(high, low);
    DCHECK(token.has_value());
    return token.value();
  }
#endif

 private:
  friend struct UnguessableTokenHash;
  explicit UnguessableToken(const Token& token);

  base::Token token_;
};

BASE_EXPORT bool operator==(const UnguessableToken& lhs,
                            const UnguessableToken& rhs);

BASE_EXPORT std::ostream& operator<<(std::ostream& out,
                                     const UnguessableToken& token);

// For use in std::unordered_map.
struct UnguessableTokenHash {
  size_t operator()(const base::UnguessableToken& token) const {
    DCHECK(token);
    return TokenHash()(token.token_);
  }
};

}  // namespace base

#endif  // BASE_UNGUESSABLE_TOKEN_H_