blob: 746666e6f3755546d2a5a51f1684a4db9b6d850d [file] [log] [blame]
// Copyright (c) 2013 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 "chrome/browser/chromeos/attestation/attestation_ca_client.h"
#include <string>
#include "base/command_line.h"
#include "chrome/browser/browser_process.h"
#include "chromeos/chromeos_switches.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
#include "net/url_request/url_request_status.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "url/gurl.h"
namespace {
// Values for the attestation server switch.
const char kAttestationServerDefault[] = "default";
const char kAttestationServerTest[] = "test";
// Endpoints for the default Google Privacy CA operations.
const char kDefaultEnrollRequestURL[] =
"https://chromeos-ca.gstatic.com/enroll";
const char kDefaultCertificateRequestURL[] =
"https://chromeos-ca.gstatic.com/sign";
// Endpoints for the test Google Privacy CA operations.
const char kTestEnrollRequestURL[] =
"https://asbestos-qa.corp.google.com/enroll";
const char kTestCertificateRequestURL[] =
"https://asbestos-qa.corp.google.com/sign";
const char kMimeContentType[] = "application/octet-stream";
} // namespace
namespace chromeos {
namespace attestation {
static PrivacyCAType GetAttestationServerType() {
std::string value =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
chromeos::switches::kAttestationServer);
if (value.empty() || value == kAttestationServerDefault) {
return DEFAULT_PCA;
}
if (value == kAttestationServerTest) {
return TEST_PCA;
}
LOG(WARNING) << "Invalid attestation server value: " << value
<< ". Using default.";
return DEFAULT_PCA;
}
AttestationCAClient::AttestationCAClient() {
pca_type_ = GetAttestationServerType();
}
AttestationCAClient::~AttestationCAClient() {}
void AttestationCAClient::SendEnrollRequest(const std::string& request,
const DataCallback& on_response) {
FetchURL(
GetType() == TEST_PCA ? kTestEnrollRequestURL : kDefaultEnrollRequestURL,
request, on_response);
}
void AttestationCAClient::SendCertificateRequest(
const std::string& request,
const DataCallback& on_response) {
FetchURL(GetType() == TEST_PCA ? kTestCertificateRequestURL
: kDefaultCertificateRequestURL,
request, on_response);
}
void AttestationCAClient::OnURLLoadComplete(
std::list<std::unique_ptr<network::SimpleURLLoader>>::iterator it,
const DataCallback& callback,
std::unique_ptr<std::string> response_body) {
// Move the loader out of the active loaders list.
std::unique_ptr<network::SimpleURLLoader> url_loader = std::move(*it);
url_loaders_.erase(it);
DCHECK(url_loader);
int response_code = -1;
if (url_loader->ResponseInfo() && url_loader->ResponseInfo()->headers) {
response_code = url_loader->ResponseInfo()->headers->response_code();
}
if (response_code < 200 || response_code > 299) {
LOG(ERROR) << "Attestation CA sent an error response: " << response_code;
callback.Run(false, "");
return;
}
if (!response_body) {
LOG(ERROR) << "Attestation CA request failed, error: "
<< url_loader->NetError();
callback.Run(false, "");
return;
}
// Run the callback last because it may delete |this|.
callback.Run(true, *response_body);
}
void AttestationCAClient::FetchURL(const std::string& url,
const std::string& request,
const DataCallback& on_response) {
const net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("attestation_ca_client", R"(
semantics {
sender: "Attestation CA client"
description:
"Sends requests to the Attestation CA as part of the remote "
"attestation feature, such as enrolling for remote attestation or "
"to obtain an attestation certificate."
trigger:
"Device enrollment, content protection or get an attestation "
"certificate for a hardware-protected key."
data:
"The data from AttestationCertificateRequest or from "
"AttestationEnrollmentRequest message from "
"cryptohome/attestation.proto. Some of the important data being "
"encrypted endorsement certificate, attestation identity public "
"key, PCR0 and PCR1 TPM values."
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: NO
setting:
"The device setting DeviceAttestationEnabled can disable the "
"attestation requests and AttestationForContentProtectionEnabled "
"can disable the attestation for content protection. But they "
"cannot be controlled by a policy or through settings."
policy_exception_justification: "Not implemented."
})");
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = GURL(url);
resource_request->method = "POST";
resource_request->load_flags = net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SAVE_COOKIES |
net::LOAD_DISABLE_CACHE;
auto url_loader = network::SimpleURLLoader::Create(
std::move(resource_request), traffic_annotation);
url_loader->AttachStringForUpload(request, kMimeContentType);
auto* raw_url_loader = url_loader.get();
url_loaders_.push_back(std::move(url_loader));
raw_url_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
g_browser_process->shared_url_loader_factory().get(),
base::BindOnce(&AttestationCAClient::OnURLLoadComplete,
base::Unretained(this), std::move(--url_loaders_.end()),
on_response));
}
PrivacyCAType AttestationCAClient::GetType() {
return pca_type_;
}
} // namespace attestation
} // namespace chromeos