1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "services/network/trust_tokens/trust_token_store.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/optional.h"
11 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
12 #include "services/network/public/cpp/is_potentially_trustworthy.h"
13 #include "services/network/public/cpp/trust_token_parameterization.h"
14 #include "services/network/public/mojom/trust_tokens.mojom-forward.h"
15 #include "services/network/trust_tokens/in_memory_trust_token_persister.h"
16 #include "services/network/trust_tokens/proto/public.pb.h"
17 #include "services/network/trust_tokens/proto/storage.pb.h"
18 #include "services/network/trust_tokens/suitable_trust_token_origin.h"
19 #include "services/network/trust_tokens/trust_token_key_commitment_getter.h"
20 #include "services/network/trust_tokens/trust_token_parameterization.h"
21 #include "services/network/trust_tokens/types.h"
22 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
23 #include "url/origin.h"
24 
25 namespace network {
26 
27 namespace {
28 class NeverExpiringExpiryDelegate
29     : public TrustTokenStore::RecordExpiryDelegate {
30  public:
IsRecordExpired(const TrustTokenRedemptionRecord & record,const SuitableTrustTokenOrigin & issuer)31   bool IsRecordExpired(const TrustTokenRedemptionRecord& record,
32                        const SuitableTrustTokenOrigin& issuer) override {
33     return false;
34   }
35 };
36 
37 }  // namespace
38 
TrustTokenStore(std::unique_ptr<TrustTokenPersister> persister,std::unique_ptr<RecordExpiryDelegate> expiry_delegate)39 TrustTokenStore::TrustTokenStore(
40     std::unique_ptr<TrustTokenPersister> persister,
41     std::unique_ptr<RecordExpiryDelegate> expiry_delegate)
42     : persister_(std::move(persister)),
43       record_expiry_delegate_(std::move(expiry_delegate)) {
44   DCHECK(persister_);
45 }
46 
47 TrustTokenStore::~TrustTokenStore() = default;
48 
CreateForTesting(std::unique_ptr<TrustTokenPersister> persister,std::unique_ptr<RecordExpiryDelegate> expiry_delegate)49 std::unique_ptr<TrustTokenStore> TrustTokenStore::CreateForTesting(
50     std::unique_ptr<TrustTokenPersister> persister,
51     std::unique_ptr<RecordExpiryDelegate> expiry_delegate) {
52   if (!persister)
53     persister = std::make_unique<InMemoryTrustTokenPersister>();
54   if (!expiry_delegate)
55     expiry_delegate = std::make_unique<NeverExpiringExpiryDelegate>();
56   return std::make_unique<TrustTokenStore>(std::move(persister),
57                                            std::move(expiry_delegate));
58 }
59 
RecordIssuance(const SuitableTrustTokenOrigin & issuer)60 void TrustTokenStore::RecordIssuance(const SuitableTrustTokenOrigin& issuer) {
61   SuitableTrustTokenOrigin issuer_origin = issuer;
62   std::unique_ptr<TrustTokenIssuerConfig> config =
63       persister_->GetIssuerConfig(issuer);
64   if (!config)
65     config = std::make_unique<TrustTokenIssuerConfig>();
66   config->set_last_issuance(internal::TimeToString(base::Time::Now()));
67   persister_->SetIssuerConfig(issuer, std::move(config));
68 }
69 
TimeSinceLastIssuance(const SuitableTrustTokenOrigin & issuer)70 base::Optional<base::TimeDelta> TrustTokenStore::TimeSinceLastIssuance(
71     const SuitableTrustTokenOrigin& issuer) {
72   std::unique_ptr<TrustTokenIssuerConfig> config =
73       persister_->GetIssuerConfig(issuer);
74   if (!config)
75     return base::nullopt;
76   if (!config->has_last_issuance())
77     return base::nullopt;
78   base::Optional<base::Time> maybe_last_issuance =
79       internal::StringToTime(config->last_issuance());
80   if (!maybe_last_issuance)
81     return base::nullopt;
82 
83   base::TimeDelta ret = base::Time::Now() - *maybe_last_issuance;
84   if (ret < base::TimeDelta())
85     return base::nullopt;
86 
87   return ret;
88 }
89 
RecordRedemption(const SuitableTrustTokenOrigin & issuer,const SuitableTrustTokenOrigin & top_level)90 void TrustTokenStore::RecordRedemption(
91     const SuitableTrustTokenOrigin& issuer,
92     const SuitableTrustTokenOrigin& top_level) {
93   std::unique_ptr<TrustTokenIssuerToplevelPairConfig> config =
94       persister_->GetIssuerToplevelPairConfig(issuer, top_level);
95   if (!config)
96     config = std::make_unique<TrustTokenIssuerToplevelPairConfig>();
97   config->set_last_redemption(internal::TimeToString(base::Time::Now()));
98   persister_->SetIssuerToplevelPairConfig(issuer, top_level, std::move(config));
99 }
100 
TimeSinceLastRedemption(const SuitableTrustTokenOrigin & issuer,const SuitableTrustTokenOrigin & top_level)101 base::Optional<base::TimeDelta> TrustTokenStore::TimeSinceLastRedemption(
102     const SuitableTrustTokenOrigin& issuer,
103     const SuitableTrustTokenOrigin& top_level) {
104   auto config = persister_->GetIssuerToplevelPairConfig(issuer, top_level);
105   if (!config)
106     return base::nullopt;
107   if (!config->has_last_redemption())
108     return base::nullopt;
109   base::Optional<base::Time> maybe_last_redemption =
110       internal::StringToTime(config->last_redemption());
111   // internal::StringToTime can fail in the case of data corruption (or writer
112   // error).
113   if (!maybe_last_redemption)
114     return base::nullopt;
115 
116   base::TimeDelta ret = base::Time::Now() - *maybe_last_redemption;
117   if (ret < base::TimeDelta())
118     return base::nullopt;
119   return ret;
120 }
121 
IsAssociated(const SuitableTrustTokenOrigin & issuer,const SuitableTrustTokenOrigin & top_level)122 bool TrustTokenStore::IsAssociated(const SuitableTrustTokenOrigin& issuer,
123                                    const SuitableTrustTokenOrigin& top_level) {
124   std::unique_ptr<TrustTokenToplevelConfig> config =
125       persister_->GetToplevelConfig(top_level);
126   if (!config)
127     return false;
128   return base::Contains(config->associated_issuers(), issuer.Serialize());
129 }
130 
SetAssociation(const SuitableTrustTokenOrigin & issuer,const SuitableTrustTokenOrigin & top_level)131 bool TrustTokenStore::SetAssociation(
132     const SuitableTrustTokenOrigin& issuer,
133     const SuitableTrustTokenOrigin& top_level) {
134   std::unique_ptr<TrustTokenToplevelConfig> config =
135       persister_->GetToplevelConfig(top_level);
136   if (!config)
137     config = std::make_unique<TrustTokenToplevelConfig>();
138   auto string_issuer = issuer.Serialize();
139 
140   if (base::Contains(config->associated_issuers(), string_issuer))
141     return true;
142 
143   if (config->associated_issuers_size() >=
144       kTrustTokenPerToplevelMaxNumberOfAssociatedIssuers) {
145     return false;
146   }
147 
148   config->add_associated_issuers(std::move(string_issuer));
149   persister_->SetToplevelConfig(top_level, std::move(config));
150 
151   return true;
152 }
153 
PruneStaleIssuerState(const SuitableTrustTokenOrigin & issuer,const std::vector<mojom::TrustTokenVerificationKeyPtr> & keys)154 void TrustTokenStore::PruneStaleIssuerState(
155     const SuitableTrustTokenOrigin& issuer,
156     const std::vector<mojom::TrustTokenVerificationKeyPtr>& keys) {
157   DCHECK([&keys]() {
158     std::set<base::StringPiece> unique_keys;
159     for (const auto& key : keys)
160       unique_keys.insert(base::StringPiece(key->body));
161     return unique_keys.size() == keys.size();
162   }());
163 
164   std::unique_ptr<TrustTokenIssuerConfig> config =
165       persister_->GetIssuerConfig(issuer);
166   if (!config)
167     config = std::make_unique<TrustTokenIssuerConfig>();
168 
169   google::protobuf::RepeatedPtrField<TrustToken> filtered_tokens;
170   for (auto& token : *config->mutable_tokens()) {
171     if (std::any_of(keys.begin(), keys.end(),
172                     [&token](const mojom::TrustTokenVerificationKeyPtr& key) {
173                       return key->body == token.signing_key();
174                     }))
175       *filtered_tokens.Add() = std::move(token);
176   }
177 
178   config->mutable_tokens()->Swap(&filtered_tokens);
179 
180   persister_->SetIssuerConfig(issuer, std::move(config));
181 }
182 
AddTokens(const SuitableTrustTokenOrigin & issuer,base::span<const std::string> token_bodies,base::StringPiece issuing_key)183 void TrustTokenStore::AddTokens(const SuitableTrustTokenOrigin& issuer,
184                                 base::span<const std::string> token_bodies,
185                                 base::StringPiece issuing_key) {
186   auto config = persister_->GetIssuerConfig(issuer);
187   if (!config)
188     config = std::make_unique<TrustTokenIssuerConfig>();
189 
190   for (auto it = token_bodies.begin();
191        it != token_bodies.end() &&
192        config->tokens_size() < kTrustTokenPerIssuerTokenCapacity;
193        ++it) {
194     TrustToken* entry = config->add_tokens();
195     entry->set_body(*it);
196     entry->set_signing_key(std::string(issuing_key));
197   }
198 
199   persister_->SetIssuerConfig(issuer, std::move(config));
200 }
201 
CountTokens(const SuitableTrustTokenOrigin & issuer)202 int TrustTokenStore::CountTokens(const SuitableTrustTokenOrigin& issuer) {
203   auto config = persister_->GetIssuerConfig(issuer);
204   if (!config)
205     return 0;
206   return config->tokens_size();
207 }
208 
RetrieveMatchingTokens(const SuitableTrustTokenOrigin & issuer,base::RepeatingCallback<bool (const std::string &)> key_matcher)209 std::vector<TrustToken> TrustTokenStore::RetrieveMatchingTokens(
210     const SuitableTrustTokenOrigin& issuer,
211     base::RepeatingCallback<bool(const std::string&)> key_matcher) {
212   auto config = persister_->GetIssuerConfig(issuer);
213   std::vector<TrustToken> matching_tokens;
214   if (!config)
215     return matching_tokens;
216 
217   std::copy_if(config->tokens().begin(), config->tokens().end(),
218                std::back_inserter(matching_tokens),
219                [&key_matcher](const TrustToken& token) {
220                  return token.has_signing_key() &&
221                         key_matcher.Run(token.signing_key());
222                });
223 
224   return matching_tokens;
225 }
226 
DeleteToken(const SuitableTrustTokenOrigin & issuer,const TrustToken & to_delete)227 void TrustTokenStore::DeleteToken(const SuitableTrustTokenOrigin& issuer,
228                                   const TrustToken& to_delete) {
229   auto config = persister_->GetIssuerConfig(issuer);
230   if (!config)
231     return;
232 
233   for (auto it = config->mutable_tokens()->begin();
234        it != config->mutable_tokens()->end(); ++it) {
235     if (it->body() == to_delete.body()) {
236       config->mutable_tokens()->erase(it);
237       break;
238     }
239   }
240 
241   persister_->SetIssuerConfig(issuer, std::move(config));
242 }
243 
SetRedemptionRecord(const SuitableTrustTokenOrigin & issuer,const SuitableTrustTokenOrigin & top_level,const TrustTokenRedemptionRecord & record)244 void TrustTokenStore::SetRedemptionRecord(
245     const SuitableTrustTokenOrigin& issuer,
246     const SuitableTrustTokenOrigin& top_level,
247     const TrustTokenRedemptionRecord& record) {
248   auto config = persister_->GetIssuerToplevelPairConfig(issuer, top_level);
249   if (!config)
250     config = std::make_unique<TrustTokenIssuerToplevelPairConfig>();
251   *config->mutable_redemption_record() = record;
252   persister_->SetIssuerToplevelPairConfig(issuer, top_level, std::move(config));
253 }
254 
255 base::Optional<TrustTokenRedemptionRecord>
RetrieveNonstaleRedemptionRecord(const SuitableTrustTokenOrigin & issuer,const SuitableTrustTokenOrigin & top_level)256 TrustTokenStore::RetrieveNonstaleRedemptionRecord(
257     const SuitableTrustTokenOrigin& issuer,
258     const SuitableTrustTokenOrigin& top_level) {
259   auto config = persister_->GetIssuerToplevelPairConfig(issuer, top_level);
260   if (!config)
261     return base::nullopt;
262 
263   if (!config->has_redemption_record())
264     return base::nullopt;
265 
266   if (record_expiry_delegate_->IsRecordExpired(config->redemption_record(),
267                                                issuer))
268     return base::nullopt;
269 
270   return config->redemption_record();
271 }
272 
ClearDataForFilter(mojom::ClearDataFilterPtr filter)273 bool TrustTokenStore::ClearDataForFilter(mojom::ClearDataFilterPtr filter) {
274   if (!filter) {
275     return persister_->DeleteForOrigins(base::BindRepeating(
276         [](const SuitableTrustTokenOrigin&) { return true; }));
277   }
278 
279   // Returns whether |storage_key|'s data should be deleted, based on the logic
280   // |filter| specifies. (Default to deleting everything, because a null
281   // |filter| is a wildcard.)
282   auto matcher = base::BindRepeating(
283       [](const mojom::ClearDataFilter& filter,
284          const SuitableTrustTokenOrigin& storage_key) -> bool {
285         // Match an origin if
286         // - it is an eTLD+1 (aka "domain and registry") match with anything
287         // on |filter|'s domain list, or
288         // - it is an origin match with anything on |filter|'s origin list.
289         bool is_match = base::Contains(filter.origins, storage_key.origin());
290 
291         // Computing the domain might be a little expensive, so
292         // skip it if we know for sure the origin is a match because it
293         // matches the origin list.
294         if (!is_match) {
295           std::string etld1_for_origin =
296               net::registry_controlled_domains::GetDomainAndRegistry(
297                   storage_key.origin(),
298                   net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
299           is_match = base::Contains(filter.domains, etld1_for_origin);
300         }
301 
302         switch (filter.type) {
303           case mojom::ClearDataFilter::Type::KEEP_MATCHES:
304             return !is_match;
305           case mojom::ClearDataFilter::Type::DELETE_MATCHES:
306             return is_match;
307         }
308       },
309       *filter);
310 
311   return persister_->DeleteForOrigins(std::move(matcher));
312 }
313 
314 }  // namespace network
315