blob: c5b9d704be5c1cd5bfec12698ff400d8942303b2 [file] [log] [blame]
// Copyright 2020 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 "services/network/trust_tokens/trust_token_request_helper_factory.h"
#include <memory>
#include <utility>
#include "base/callback_forward.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/strcat.h"
#include "net/base/isolation_info.h"
#include "net/log/net_log_event_type.h"
#include "net/log/net_log_with_source.h"
#include "net/url_request/url_request.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/trust_token_http_headers.h"
#include "services/network/public/cpp/trust_token_parameterization.h"
#include "services/network/public/mojom/trust_tokens.mojom-shared.h"
#include "services/network/trust_tokens/boringssl_trust_token_issuance_cryptographer.h"
#include "services/network/trust_tokens/boringssl_trust_token_redemption_cryptographer.h"
#include "services/network/trust_tokens/ed25519_key_pair_generator.h"
#include "services/network/trust_tokens/ed25519_trust_token_request_signer.h"
#include "services/network/trust_tokens/local_trust_token_operation_delegate.h"
#include "services/network/trust_tokens/local_trust_token_operation_delegate_impl.h"
#include "services/network/trust_tokens/operating_system_matching.h"
#include "services/network/trust_tokens/suitable_trust_token_origin.h"
#include "services/network/trust_tokens/trust_token_key_commitment_controller.h"
#include "services/network/trust_tokens/trust_token_parameterization.h"
#include "services/network/trust_tokens/trust_token_request_canonicalizer.h"
#include "services/network/trust_tokens/trust_token_request_redemption_helper.h"
#include "services/network/trust_tokens/trust_token_request_signing_helper.h"
#include "services/network/trust_tokens/types.h"
namespace network {
namespace {
using Outcome = internal::TrustTokenRequestHelperFactoryOutcome;
base::StringPiece OutcomeToString(Outcome outcome) {
switch (outcome) {
case Outcome::kSuccessfullyCreatedAnIssuanceHelper:
return "Successfully created an issuance helper";
case Outcome::kSuccessfullyCreatedARedemptionHelper:
return "Successfully created a redemption helper";
case Outcome::kSuccessfullyCreatedASigningHelper:
return "Successfully created a signing helper";
case Outcome::kEmptyIssuersParameter:
return "Empty 'issuers' parameter";
case Outcome::kUnsuitableIssuerInIssuersParameter:
return "Unsuitable issuer in 'issuers' parameter";
case Outcome::kUnsuitableTopFrameOrigin:
return "Unsuitable top frame origin";
case Outcome::kRequestRejectedDueToBearingAnInternalTrustTokensHeader:
return "Request rejected due to bearing an internal Trust Tokens header";
case Outcome::kRejectedByAuthorizer:
return "Rejected by authorizer (check cookie settings?)";
}
}
void LogOutcome(const net::NetLogWithSource& log,
mojom::TrustTokenOperationType type,
Outcome outcome) {
base::UmaHistogramEnumeration(
base::StrCat({"Net.TrustTokens.RequestHelperFactoryOutcome.",
internal::TrustTokenOperationTypeToString(type)}),
outcome);
log.EndEvent(net::NetLogEventType::TRUST_TOKEN_OPERATION_REQUESTED,
[outcome]() {
base::Value ret(base::Value::Type::DICTIONARY);
ret.SetStringKey("outcome", OutcomeToString(outcome));
return ret;
});
}
} // namespace
TrustTokenRequestHelperFactory::TrustTokenRequestHelperFactory(
PendingTrustTokenStore* store,
const TrustTokenKeyCommitmentGetter* key_commitment_getter,
base::RepeatingCallback<mojom::NetworkContextClient*(void)>
context_client_provider,
base::RepeatingCallback<bool(void)> authorizer)
: store_(store),
key_commitment_getter_(key_commitment_getter),
context_client_provider_(std::move(context_client_provider)),
authorizer_(std::move(authorizer)) {}
TrustTokenRequestHelperFactory::~TrustTokenRequestHelperFactory() = default;
void TrustTokenRequestHelperFactory::CreateTrustTokenHelperForRequest(
const net::URLRequest& request,
const mojom::TrustTokenParams& params,
base::OnceCallback<void(TrustTokenStatusOrRequestHelper)> done) {
request.net_log().BeginEventWithIntParams(
net::NetLogEventType::TRUST_TOKEN_OPERATION_REQUESTED,
"Operation type (mojom.TrustTokenOperationType)",
static_cast<int>(params.type));
if (!authorizer_.Run()) {
LogOutcome(request.net_log(), params.type, Outcome::kRejectedByAuthorizer);
std::move(done).Run(mojom::TrustTokenOperationStatus::kUnavailable);
return;
}
for (base::StringPiece header : TrustTokensRequestHeaders()) {
if (request.extra_request_headers().HasHeader(header)) {
LogOutcome(
request.net_log(), params.type,
Outcome::kRequestRejectedDueToBearingAnInternalTrustTokensHeader);
std::move(done).Run(mojom::TrustTokenOperationStatus::kInvalidArgument);
return;
}
}
base::Optional<SuitableTrustTokenOrigin> maybe_top_frame_origin;
if (request.isolation_info().top_frame_origin()) {
maybe_top_frame_origin = SuitableTrustTokenOrigin::Create(
*request.isolation_info().top_frame_origin());
}
if (!maybe_top_frame_origin) {
LogOutcome(request.net_log(), params.type,
Outcome::kUnsuitableTopFrameOrigin);
std::move(done).Run(mojom::TrustTokenOperationStatus::kFailedPrecondition);
return;
}
store_->ExecuteOrEnqueue(base::BindOnce(
&TrustTokenRequestHelperFactory::ConstructHelperUsingStore,
weak_factory_.GetWeakPtr(), *maybe_top_frame_origin,
base::Passed(params.Clone()), request.net_log(), std::move(done)));
}
void TrustTokenRequestHelperFactory::ConstructHelperUsingStore(
SuitableTrustTokenOrigin top_frame_origin,
mojom::TrustTokenParamsPtr params,
net::NetLogWithSource net_log,
base::OnceCallback<void(TrustTokenStatusOrRequestHelper)> done,
TrustTokenStore* store) {
DCHECK(params);
switch (params->type) {
case mojom::TrustTokenOperationType::kIssuance: {
LogOutcome(net_log, params->type,
Outcome::kSuccessfullyCreatedAnIssuanceHelper);
std::move(done).Run(std::unique_ptr<TrustTokenRequestHelper>(
new TrustTokenRequestIssuanceHelper(
std::move(top_frame_origin), store, key_commitment_getter_,
std::make_unique<BoringsslTrustTokenIssuanceCryptographer>(),
std::make_unique<LocalTrustTokenOperationDelegateImpl>(
context_client_provider_),
base::BindRepeating(&IsCurrentOperatingSystem),
std::move(net_log))));
return;
}
case mojom::TrustTokenOperationType::kRedemption: {
LogOutcome(net_log, params->type,
Outcome::kSuccessfullyCreatedARedemptionHelper);
std::move(done).Run(std::unique_ptr<TrustTokenRequestHelper>(
new TrustTokenRequestRedemptionHelper(
std::move(top_frame_origin), params->refresh_policy, store,
key_commitment_getter_,
std::make_unique<Ed25519KeyPairGenerator>(),
std::make_unique<BoringsslTrustTokenRedemptionCryptographer>(),
std::move(net_log))));
return;
}
case mojom::TrustTokenOperationType::kSigning: {
if (params->issuers.empty()) {
LogOutcome(net_log, params->type, Outcome::kEmptyIssuersParameter);
std::move(done).Run(mojom::TrustTokenOperationStatus::kInvalidArgument);
return;
}
std::vector<SuitableTrustTokenOrigin> issuers;
for (url::Origin& potentially_unsuitable_issuer : params->issuers) {
base::Optional<SuitableTrustTokenOrigin> maybe_issuer =
SuitableTrustTokenOrigin::Create(
std::move(potentially_unsuitable_issuer));
if (!maybe_issuer) {
LogOutcome(net_log, params->type,
Outcome::kUnsuitableIssuerInIssuersParameter);
std::move(done).Run(
mojom::TrustTokenOperationStatus::kInvalidArgument);
return;
}
issuers.emplace_back(std::move(*maybe_issuer));
}
TrustTokenRequestSigningHelper::Params signing_params(
std::move(issuers), top_frame_origin,
std::move(params->additional_signed_headers),
params->include_timestamp_header, params->sign_request_data,
params->possibly_unsafe_additional_signing_data);
LogOutcome(net_log, params->type,
Outcome::kSuccessfullyCreatedASigningHelper);
std::move(done).Run(std::unique_ptr<TrustTokenRequestHelper>(
new TrustTokenRequestSigningHelper(
store, std::move(signing_params),
std::make_unique<Ed25519TrustTokenRequestSigner>(),
std::make_unique<TrustTokenRequestCanonicalizer>(),
std::move(net_log))));
return;
}
}
}
TrustTokenStatusOrRequestHelper::TrustTokenStatusOrRequestHelper() = default;
TrustTokenStatusOrRequestHelper::TrustTokenStatusOrRequestHelper(
mojom::TrustTokenOperationStatus status)
: status_(status) {
DCHECK_NE(status_, mojom::TrustTokenOperationStatus::kOk);
}
TrustTokenStatusOrRequestHelper::TrustTokenStatusOrRequestHelper(
std::unique_ptr<TrustTokenRequestHelper> helper)
: status_(mojom::TrustTokenOperationStatus::kOk),
helper_(std::move(helper)) {
DCHECK(helper_);
}
TrustTokenStatusOrRequestHelper::~TrustTokenStatusOrRequestHelper() = default;
TrustTokenStatusOrRequestHelper::TrustTokenStatusOrRequestHelper(
TrustTokenStatusOrRequestHelper&&) = default;
TrustTokenStatusOrRequestHelper& TrustTokenStatusOrRequestHelper::operator=(
TrustTokenStatusOrRequestHelper&&) = default;
} // namespace network