Commit 8e9102fb authored by David Van Cleve's avatar David Van Cleve Committed by Commit Bot

[Trust tokens] Wrapper for protocol -> storage operations

This CL adds net::trust_tokens::Store, which translates between
Trust Tokens protocol-related operations and the underlying
key-value representation of the persistence layer
(net::trust_tokens::Persister).

Bug: 1036494
Change-Id: Ida2e2f85bb473ffb8057ba96583ddc76d689d558
Cq-Do-Not-Cancel-Tryjobs: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1986383Reviewed-by: default avatarAsanka Herath <asanka@chromium.org>
Commit-Queue: David Van Cleve <davidvc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#733777}
parent 088f73dd
......@@ -6,13 +6,12 @@ import("//third_party/protobuf/proto_library.gni")
source_set("trust_tokens") {
visibility = [
"//net",
"//services/network",
":tests",
"//net/*",
"//services/network/",
]
# TODO(davidvc): Public API to be added in a subsequent CL.
public = []
public = [ "trust_token_store.h" ]
friend = [ ":tests" ]
......@@ -20,26 +19,35 @@ source_set("trust_tokens") {
"in_memory_trust_token_persister.cc",
"in_memory_trust_token_persister.h",
"trust_token_persister.h",
"trust_token_store.cc",
"types.cc",
"types.h",
]
deps = [
":public_proto",
":storage_proto",
"//base",
"//url",
]
public_deps = [ ":public_proto" ]
}
source_set("tests") {
testonly = true
sources = [ "trust_token_persister_unittest.cc" ]
sources = [
"trust_token_persister_unittest.cc",
"trust_token_store_unittest.cc",
"types_unittest.cc",
]
deps = [
":public_proto",
":storage_proto",
":trust_tokens",
"//base",
"//base/test:test_support",
"//testing/gmock",
"//testing/gtest",
"//url",
......
csharrison@chromium.org
svaldez@chromium.org
asanka@chromium.org
......@@ -8,13 +8,14 @@ package net;
option optimize_for = LITE_RUNTIME;
// A TrustTokenCommitmentKey message represents a single commitment key received
// from an issuer’s key commitments endpoint.
message TrustTokenCommitmentKey {
// The body of the keys. Used for comparison (when checking if
// A TrustTokenKeyCommitment message stores a single key received
// from an issuer’s key commitments endpoint, along with associated
// metadata.
message TrustTokenKeyCommitment {
// The key's body. Used for comparison (when checking if
// stored tokens’ keys are still current) and, by BoringSSL, for
// cryptographic operations.
optional bytes body = 1; // required
optional bytes key = 1; // required
// The expiry time of the key.
// (Here and elsewhere, string times are serialized base::Times
......@@ -36,7 +37,7 @@ message TrustToken {
// The key with which the Token was signed. Tokens
// are only provided to servers while their commitment keys
// remain active.
optional bytes commitment_key_body = 2; // required
optional bytes signing_key = 2; // required
}
// A SignedTrustTokenRedemptionRecord message stores state associated with a
......@@ -46,8 +47,9 @@ message TrustToken {
// with the SRR.
message SignedTrustTokenRedemptionRecord {
// The body of an SRR encodes information such as its top-level
// origin and its expiration time, but Chrome doesn’t control
// the encoding and uses a library to extract these values.
// origin and its expiration time. The encoding is opaque to //net; BoringSSL
// provides interfaces to read data from the body that is pertinent to
// protocol execution.
optional bytes body = 1;
// If one of public_key or signing_key is present, the other must also be
// present.
......
......@@ -10,7 +10,7 @@ option optimize_for = LITE_RUNTIME;
import "public.proto";
// An TrustTokenIssuerConfig message represents persistent state scoped
// A TrustTokenIssuerConfig message represents persistent state scoped
// to a single Trust Tokens issuer origin.
// An issuer’s config contains:
// - any signed-but-unspent tokens received from the issuer; and
......@@ -18,8 +18,8 @@ import "public.proto";
// per issuance request), if it has configured one via its key
// commitment endpoint.
message TrustTokenIssuerConfig {
// Keys the issuer has recently committed (we don’t need to store stale keys)
repeated TrustTokenCommitmentKey keys = 1;
// Keys the issuer has recently committed (no need to store stale keys)
repeated TrustTokenKeyCommitment keys = 1;
optional int32 batch_size = 2;
repeated TrustToken tokens = 3;
// The time of the most recent issuance for this pair. Used for
......
This diff is collapsed.
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_TRUST_TOKENS_TRUST_TOKEN_STORE_H_
#define NET_TRUST_TOKENS_TRUST_TOKEN_STORE_H_
#include <memory>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "net/trust_tokens/proto/public.pb.h"
#include "net/trust_tokens/trust_token_persister.h"
#include "net/trust_tokens/types.h"
#include "url/origin.h"
namespace net {
// A TrustTokenStore provides operations on persistent state necessary for
// the various steps of the Trust TrustTokens protocol.
//
// For more information about the protocol, see the explainer at
// https://github.com/WICG/trust-token-api.
//
// TrustTokenStore translates operations germane to different steps
// of token issuance, token redemption, and request signing into
// operations in the key-value representation used by the persistence
// layer.
//
// For example, it provides operations:
// - checking preconditions for the different protocol steps;
// - storing unblinded, signed tokens; and
// - managing Signed Redemption Records (SRRs) and corresponding key pairs.
//
// TrustTokenStore's methods do minimal precondition checking and, in
// particular, only selectively verify protocol-level invariants and
// input integrity.
class TrustTokenStore {
public:
class RecordExpiryDelegate {
public:
virtual ~RecordExpiryDelegate() = default;
// Returns whether the given Signed Redemption Record has expired.
// This is implemented with a delegate to abstract away reading
// the values of SRRs (they're opaque to this store).
virtual bool IsRecordExpired(
const SignedTrustTokenRedemptionRecord& record) = 0;
};
// Creates a new TrustTokenStore passing read and write operations through
// to the given persister.
//
// Until the underlying BoringSSL functionality is implemented to extract
// expiry timestamps from Signed Redemption Record bodies, defaults to
// never expiring stored SRRs.
//
// |persister| must not be null.
explicit TrustTokenStore(std::unique_ptr<TrustTokenPersister> persister);
// Creates a TrustTokenStore relying on the given delegate for judging whether
// signed redemption records have expired.
//
// |persister| must not be null.
TrustTokenStore(
std::unique_ptr<TrustTokenPersister> persister,
std::unique_ptr<RecordExpiryDelegate> expiry_delegate_for_testing);
virtual ~TrustTokenStore();
//// Methods related to ratelimits:
// Updates the given issuer's last issuance time to now.
//
// |issuer| must not be opaque.
virtual void RecordIssuance(const url::Origin& issuer);
// Returns the time since the last call to RecordIssuance for
// issuer |issuer|, or nullopt in the following two cases:
// 1. there is no currently-recorded prior issuance for the
// issuer, or
// 2. the time since the last issuance is negative (because
// of, for instance, corruption or clock skew).
//
// |issuer| must not be opaque.
WARN_UNUSED_RESULT virtual base::Optional<base::TimeDelta>
TimeSinceLastIssuance(const url::Origin& issuer);
// Updates the given (issuer, top-level) origin pair's last redemption time
// to now.
//
// |issuer| and |top_level| must not be opaque.
virtual void RecordRedemption(const url::Origin& issuer,
const url::Origin& top_level);
// Returns the time elapsed since the last redemption recorded by
// RecordRedemption for issuer |issuer| and top level |top_level|,
// or nullopt in the following two cases:
// 1. there was no prior redemption for the (issuer,
// top-level origin) pair.
// 2. the time since the last redepmption is negative (because
// of, for instance, corruption or clock skew).
//
// |issuer| and |top_level| must not be opaque.
WARN_UNUSED_RESULT virtual base::Optional<base::TimeDelta>
TimeSinceLastRedemption(const url::Origin& issuer,
const url::Origin& top_level);
// Returns whether |issuer| is associated with |top_level|.
//
// |issuer| and |top_level| must not be opaque.
WARN_UNUSED_RESULT virtual bool IsAssociated(const url::Origin& issuer,
const url::Origin& top_level);
// Associates |issuer| with |top_level|. (It's the caller's responsibility to
// enforce any cap on the number of top levels per issuer.)
//
// |issuer| and |top_level| must not be opaque.
virtual void SetAssociation(const url::Origin& issuer,
const url::Origin& top_level);
//// Methods related to reading and writing issuer values configured via key
//// commitment queries, such as key commitments and batch sizes:
// Returns all stored key commitments (including related metadata:
// see the definition of TrustTokenKeyCommitment) for the given issuer.
//
// |issuer| must not be opaque.
WARN_UNUSED_RESULT virtual std::vector<TrustTokenKeyCommitment>
KeyCommitments(const url::Origin& issuer);
// Sets the key commitments for |issuer| to exactly the keys in |keys|.
// If there is a key in |keys| with the same key() as a key already stored:
// - maintains the "first seen at" time for the key
// - updates the expiry date to the new expiry date, even if it is sooner
// than the previous expiry date
//
// Also prunes all state corresponding to keys *not* in |keys|:
// - removes all stored signed tokens for |issuer| that were signed with
// keys not in |keys|
// - removes all key commitments for |issuer| with keys not in |keys|
//
// It is the client's responsibility to validate the
// reasonableness of the given keys' expiry times. (For instance, one might
// wish to avoid providing keys with expiry times in the past.)
//
// |issuer| must not be opaque, and the commitments in |keys| must have
// distinct keys.
virtual void SetKeyCommitmentsAndPruneStaleState(
const url::Origin& issuer,
base::span<const TrustTokenKeyCommitment> keys);
// Returns the "batch size" (number of blinded tokens to provide per issuance
// request) for the given issuer, if present and greater than 0. Otherwise,
// returns nullopt.
//
// |issuer| must not be opaque.
WARN_UNUSED_RESULT virtual base::Optional<int> BatchSize(
const url::Origin& issuer);
// Sets the given issuer's batch size (see above).
//
// |issuer| must not be opaque; |batch_size| must be at least 1.
virtual void SetBatchSize(const url::Origin& issuer, int batch_size);
//// Methods related to reading and writing signed tokens:
// Associates to the given issuer additional signed
// trust tokens with:
// - token bodies given by |token_bodies|
// - signing keys given by |issuing_key|.
//
// |issuer| must not be opaque and must have a stored
// key commitment corresponding to |issuing_key|.
virtual void AddTokens(const url::Origin& issuer,
base::span<const std::string> token_bodies,
base::StringPiece issuing_key);
// Returns all signed tokens from |issuer| signed by keys matching
// the given predicate.
//
// |issuer| must not be opaque.
WARN_UNUSED_RESULT virtual std::vector<TrustToken> RetrieveMatchingTokens(
const url::Origin& issuer,
base::RepeatingCallback<bool(const std::string&)> key_matcher);
// If |to_delete| is a token issued by |issuer|, deletes the token.
//
// |issuer| must not be opaque.
void DeleteToken(const url::Origin& issuer, const TrustToken& to_delete);
//// Methods concerning Signed Redemption Records (SRRs)
// Sets the cached SRR corresponding to the pair (issuer, top_level)
// to |record|. Overwrites any existing record.
//
// |issuer| and |top_level| must not be opaque.
virtual void SetRedemptionRecord(
const url::Origin& issuer,
const url::Origin& top_level,
const SignedTrustTokenRedemptionRecord& record);
// Attempts to retrieve the stored SRR for the given pair of (issuer,
// top-level) origins.
// - If the pair has a current (i.e., non-expired) SRR, returns that SRR.
// - Otherwise, returns nullopt.
//
// |issuer| and |top_level| must not be opaque.
WARN_UNUSED_RESULT virtual base::Optional<SignedTrustTokenRedemptionRecord>
RetrieveNonstaleRedemptionRecord(const url::Origin& issuer,
const url::Origin& top_level);
private:
std::unique_ptr<TrustTokenPersister> persister_;
std::unique_ptr<RecordExpiryDelegate> record_expiry_delegate_;
};
} // namespace net
#endif // NET_TRUST_TOKENS_TRUST_TOKEN_STORE_H_
This diff is collapsed.
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/trust_tokens/types.h"
#include "base/time/time.h"
#include "base/value_conversions.h"
#include "base/values.h"
#include "url/origin.h"
namespace net {
namespace internal {
base::Optional<base::Time> StringToTime(base::StringPiece my_string) {
base::Time ret;
if (!base::GetValueAsTime(base::Value(my_string), &ret))
return base::nullopt;
return ret;
}
std::string TimeToString(base::Time my_time) {
return base::CreateTimeValue(my_time).GetString();
}
} // namespace internal
} // namespace net
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_TRUST_TOKENS_TYPES_H_
#define NET_TRUST_TOKENS_TYPES_H_
#include <string>
#include "base/strings/string_piece_forward.h"
#include "base/time/time.h"
#include "url/origin.h"
namespace net {
namespace internal {
// types.h provides utility functions for Trust TrustTokens type conversion.
// Deserializes a base::Time. Returns nullopt on failure (for instance,
// deserialization can fail if |my_string| is malformed due to data
// corruption) and the deserialized Time on success.
base::Optional<base::Time> StringToTime(base::StringPiece my_string);
// Serializes a base::Time.
std::string TimeToString(base::Time my_time);
} // namespace internal
} // namespace net
#endif // NET_TRUST_TOKENS_TYPES_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/trust_tokens/types.h"
#include "base/time/time.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Optional;
namespace net {
namespace internal {
// trust_tokens/types.h's TimeToString/StringToTime implementations are
// thin wrappers around well-tested //base conversion methods, so these
// tests are just sanity checks to make sure that values are actually
// getting passed to the pertinent //base libraries.
TEST(TrustTokenTypes, TimeToStringRoundtrip) {
auto my_time = base::Time::UnixEpoch() + base::TimeDelta::FromMilliseconds(
373849174829374); // arbitrary
EXPECT_THAT(StringToTime(TimeToString(my_time)), Optional(my_time));
}
TEST(TrustTokenTypes, TimeFromBadStringFails) {
EXPECT_EQ(StringToTime("I bet this isn't a valid representation of a time."),
base::nullopt);
}
} // namespace internal
} // namespace net
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment