blob: 7a419a0f789f035c21e00569fcf95ef4aad2823c [file] [log] [blame]
// Copyright 2021 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 CONTENT_BROWSER_AGGREGATION_SERVICE_AGGREGATABLE_REPORT_H_
#define CONTENT_BROWSER_AGGREGATION_SERVICE_AGGREGATABLE_REPORT_H_
#include <stddef.h>
#include <stdint.h>
#include <ostream>
#include <string>
#include <vector>
#include "base/time/time.h"
#include "base/values.h"
#include "content/browser/aggregation_service/public_key.h"
#include "content/common/content_export.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/origin.h"
namespace content {
class AggregatableReportRequest;
// The underlying private information which will be sent to the processing
// origins for aggregation. Each payload encodes a single contribution to a
// histogram bucket. This will be encrypted and won't be readable by the
// reporting endpoint.
struct CONTENT_EXPORT AggregationServicePayloadContents {
// TODO(alexmt): Add kDistinctCount option.
enum class Operation {
kHierarchicalHistogram = 0,
kMaxValue = kHierarchicalHistogram,
};
// TODO(crbug.com/1228501): Add kSingleServer option.
enum class ProcessingType {
kTwoParty = 0,
kMaxValue = kTwoParty,
};
AggregationServicePayloadContents(Operation operation,
int bucket,
int value,
ProcessingType processing_type,
url::Origin reporting_origin);
Operation operation;
int bucket;
int value;
ProcessingType processing_type;
url::Origin reporting_origin;
};
// Represents the information that will be provided to both the reporting
// endpoint and the processing origin(s), i.e. stored in the encrypted payload
// and in the plaintext report.
struct CONTENT_EXPORT AggregatableReportSharedInfo {
AggregatableReportSharedInfo(base::Time scheduled_report_time,
std::string privacy_budget_key);
base::Time scheduled_report_time;
std::string privacy_budget_key;
};
// An AggregatableReport contains all the information needed for sending the
// report to its reporting endpoint. All nested information has already been
// serialized and encrypted as necessary.
class CONTENT_EXPORT AggregatableReport {
public:
// This is used to encapsulate the data that is specific to a single
// processing origin.
struct CONTENT_EXPORT AggregationServicePayload {
AggregationServicePayload(url::Origin origin,
std::vector<uint8_t> payload,
std::string key_id);
AggregationServicePayload(AggregationServicePayload&& other);
AggregationServicePayload& operator=(AggregationServicePayload&& other);
~AggregationServicePayload();
url::Origin origin;
// This payload is constructed using the data in the
// AggregationServicePayloadContents and then encrypted with one of
// `origin`'s public keys. The plaintext of the encrypted payload is a
// serialized CBOR map structured as follows:
// {
// "version": "<API version>",
// "operation": "<chosen operation as string>",
// "privacy_budget_key": "<field for server to do privacy budgeting>",
// "scheduled_report_time": <timestamp in msec>,
// "reporting_origin": "https://reporter.example",
// "dpf_key": <binary serialization of the DPF key>,
// }
std::vector<uint8_t> payload;
// Indicates the chosen encryption key.
std::string key_id;
};
// Used to allow mocking `CreateFromRequestAndPublicKeys()` in tests.
class CONTENT_EXPORT Provider {
public:
virtual ~Provider();
// Generates DPF keys, serializes the information in `report_request` and
// encrypts using the `public_keys` as necessary. The order of `public_keys`
// should correspond to `report_request.processing_origins`, which should be
// sorted. Returns `absl::nullopt` if an error occurred during construction.
virtual absl::optional<AggregatableReport> CreateFromRequestAndPublicKeys(
AggregatableReportRequest report_request,
std::vector<PublicKey> public_keys) const;
// Sets whether to disable encryption of the payload(s). Should only be used
// by the AggregationServiceTool.
static void SetDisableEncryptionForTestingTool(bool should_disable);
private:
static bool g_disable_encryption_for_testing_tool_;
};
// log_2 of the number of buckets
static constexpr size_t kBucketDomainBitLength = 32;
// log_2 of the value output space
static constexpr size_t kValueDomainBitLength = 64;
static constexpr size_t kNumberOfProcessingOrigins = 2;
// Used as the authenticated information (i.e. context info). This value must
// not be reused for new protocols or versions of this protocol unless the
// ciphertexts are intended to be compatible. This ensures that, even if
// public keys are reused, the same ciphertext cannot be (i.e. no cross-
// protocol attacks).
static constexpr char kDomainSeparationValue[] = "aggregation_service";
AggregatableReport(std::vector<AggregationServicePayload> payloads,
AggregatableReportSharedInfo shared_info);
// Move-only.
AggregatableReport(AggregatableReport&& other);
AggregatableReport& operator=(AggregatableReport&& other);
~AggregatableReport();
const std::vector<AggregationServicePayload>& payloads() const {
return payloads_;
}
const AggregatableReportSharedInfo& shared_info() const {
return shared_info_;
}
// Returns the JSON representation of this report of the form
// {
// "scheduled_report_time": "<timestamp in msec>",
// "privacy_budget_key": "<field for server to do privacy budgeting>",
// "version": "<api version>",
// "aggregation_service_payloads": [
// {
// "origin": "https://helper1.example",
// "payload": "<base64 encoded encrypted data>",
// "key_id": "<string identifying public key used>"
// },
// {
// "origin": "https://helper2.example",
// "payload": "<base64 encoded encrypted data>",
// "key_id": "<string identifying public key used>"
// }
// ]
// }
// Note that APIs may wish to add additional key-value pairs to this returned
// value. `this` is required to be an rvalue to avoid unnecessary copies; this
// method should only need to be called once.
base::Value::DictStorage GetAsJson() &&;
// TODO(crbug.com/1247409): Expose static method to validate that a
// base::Value appears to represent a valid report.
private:
// This vector should have an entry for each processing origin specified in
// the original AggregatableReportRequest.
std::vector<AggregationServicePayload> payloads_;
AggregatableReportSharedInfo shared_info_;
};
// Represents a request for an AggregatableReport. Contains all the data
// necessary to construct the report except for the PublicKey for each
// processing origin.
class CONTENT_EXPORT AggregatableReportRequest {
public:
// Returns `absl::nullopt` if `processing_origins.size()` is invalid.
static absl::optional<AggregatableReportRequest> Create(
std::vector<url::Origin> processing_origins,
AggregationServicePayloadContents payload_contents,
AggregatableReportSharedInfo shared_info);
// Move-only.
AggregatableReportRequest(AggregatableReportRequest&& other);
AggregatableReportRequest& operator=(AggregatableReportRequest&& other);
~AggregatableReportRequest();
const std::vector<url::Origin>& processing_origins() const {
return processing_origins_;
}
const AggregationServicePayloadContents& payload_contents() const {
return payload_contents_;
}
const AggregatableReportSharedInfo& shared_info() const {
return shared_info_;
}
private:
// To avoid unnecessary copies, allow the provider to directly access members
// of the AggregatableReportRequest being consumed.
friend class AggregatableReport::Provider;
AggregatableReportRequest(std::vector<url::Origin> processing_origins,
AggregationServicePayloadContents payload_contents,
AggregatableReportSharedInfo shared_info);
std::vector<url::Origin> processing_origins_;
AggregationServicePayloadContents payload_contents_;
AggregatableReportSharedInfo shared_info_;
};
} // namespace content
#endif // CONTENT_BROWSER_AGGREGATION_SERVICE_AGGREGATABLE_REPORT_H_