blob: f184c9f5a726da3aad568a943ce385cfea9ca1ff [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/boringssl_trust_token_redemption_cryptographer.h"
#include "base/base64.h"
#include "base/callback_helpers.h"
#include "net/http/structured_headers.h"
#include "services/network/trust_tokens/scoped_boringssl_bytes.h"
#include "services/network/trust_tokens/signed_redemption_record_serialization.h"
#include "services/network/trust_tokens/trust_token_client_data_canonicalization.h"
#include "services/network/trust_tokens/trust_token_parameterization.h"
#include "third_party/boringssl/src/include/openssl/base.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/mem.h"
#include "third_party/boringssl/src/include/openssl/trust_token.h"
namespace network {
BoringsslTrustTokenRedemptionCryptographer::
BoringsslTrustTokenRedemptionCryptographer() = default;
BoringsslTrustTokenRedemptionCryptographer::
~BoringsslTrustTokenRedemptionCryptographer() = default;
bool BoringsslTrustTokenRedemptionCryptographer::Initialize(
int issuer_configured_batch_size,
base::StringPiece signed_redemption_record_verification_key) {
if (!base::IsValueInRangeForNumericType<size_t>(issuer_configured_batch_size))
return false;
ctx_ = bssl::UniquePtr<TRUST_TOKEN_CLIENT>(TRUST_TOKEN_CLIENT_new(
TRUST_TOKEN_experiment_v1(),
static_cast<size_t>(issuer_configured_batch_size)));
if (!ctx_)
return false;
bssl::UniquePtr<EVP_PKEY> srr_verification_pkey(EVP_PKEY_new_raw_public_key(
EVP_PKEY_ED25519,
/*unused=*/nullptr, // Yes, this parameter is called "unused".
base::as_bytes(base::make_span(signed_redemption_record_verification_key))
.data(),
signed_redemption_record_verification_key.size()));
if (!srr_verification_pkey)
return false;
if (!TRUST_TOKEN_CLIENT_set_srr_key(ctx_.get(),
srr_verification_pkey.get())) {
return false;
}
return true;
}
base::Optional<std::string>
BoringsslTrustTokenRedemptionCryptographer::BeginRedemption(
TrustToken token,
base::StringPiece verification_key_to_bind,
const url::Origin& top_level_origin) {
if (!ctx_)
return base::nullopt;
// It's unclear if BoringSSL expects the exact same value in the client data
// and as the |time| argument to TRUST_TOKEN_CLIENT_begin_redemption; play
// it safe by using a single timestamp.
base::Time redemption_timestamp = base::Time::Now();
base::Optional<std::vector<uint8_t>> maybe_client_data =
CanonicalizeTrustTokenClientDataForRedemption(
redemption_timestamp, top_level_origin, verification_key_to_bind);
if (!maybe_client_data)
return base::nullopt;
ScopedBoringsslBytes raw_redemption_request;
bssl::UniquePtr<TRUST_TOKEN> boringssl_token(
TRUST_TOKEN_new(base::as_bytes(base::make_span(token.body())).data(),
token.body().size()));
if (!boringssl_token)
return base::nullopt;
if (!TRUST_TOKEN_CLIENT_begin_redemption(
ctx_.get(), raw_redemption_request.mutable_ptr(),
raw_redemption_request.mutable_len(), boringssl_token.get(),
maybe_client_data->data(), maybe_client_data->size(),
(redemption_timestamp - base::Time::UnixEpoch()).InSeconds())) {
return base::nullopt;
}
return base::Base64Encode(raw_redemption_request.as_span());
}
base::Optional<std::string>
BoringsslTrustTokenRedemptionCryptographer::ConfirmRedemption(
base::StringPiece response_header) {
if (!ctx_)
return base::nullopt;
std::string decoded_response;
if (!base::Base64Decode(response_header, &decoded_response))
return base::nullopt;
// |srr_body| and |srr_signature| together provide the information in the
// signed redemption record (see ConstructSignedRedemptionRecord's function
// comment for more information).
ScopedBoringsslBytes srr_body;
ScopedBoringsslBytes srr_signature;
if (!TRUST_TOKEN_CLIENT_finish_redemption(
ctx_.get(), srr_body.mutable_ptr(), srr_body.mutable_len(),
srr_signature.mutable_ptr(), srr_signature.mutable_len(),
base::as_bytes(base::make_span(decoded_response)).data(),
decoded_response.size())) {
return base::nullopt;
}
return ConstructSignedRedemptionRecord(srr_body.as_span(),
srr_signature.as_span());
}
} // namespace network