blob: dcc8377a47c9a1bbfac4be9817a21cf2a2ad8057 [file] [log] [blame]
// Copyright 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 "extensions/browser/api/messaging/message_property_provider.h"
#include <stdint.h>
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "crypto/ec_private_key.h"
#include "extensions/common/api/runtime.h"
#include "net/base/completion_callback.h"
#include "net/cert/asn1_util.h"
#include "net/cert/jwk_serializer.h"
#include "net/ssl/channel_id_service.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
namespace extensions {
MessagePropertyProvider::MessagePropertyProvider() {}
void MessagePropertyProvider::GetChannelID(
content::StoragePartition* storage_partition,
const GURL& source_url,
const ChannelIDCallback& reply) {
if (!source_url.is_valid()) {
// This isn't a real URL, so there's no sense in looking for a channel ID
// for it. Dispatch with an empty tls channel ID.
reply.Run(std::string());
return;
}
content::ScopedAllowGetURLRequestContext scoped_allow_get_url_request_context;
scoped_refptr<net::URLRequestContextGetter> request_context_getter =
storage_partition->GetURLRequestContext();
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&MessagePropertyProvider::GetChannelIDOnIOThread,
base::ThreadTaskRunnerHandle::Get(),
request_context_getter, source_url.host(), reply));
}
// Helper struct to bind the memory addresses that will be written to by
// ChannelIDService::GetChannelID to the callback provided to
// MessagePropertyProvider::GetChannelID.
struct MessagePropertyProvider::GetChannelIDOutput {
std::unique_ptr<crypto::ECPrivateKey> channel_id_key;
net::ChannelIDService::Request request;
};
// static
void MessagePropertyProvider::GetChannelIDOnIOThread(
scoped_refptr<base::TaskRunner> original_task_runner,
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
const std::string& host,
const ChannelIDCallback& reply) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
const net::HttpNetworkSession::Params* network_params =
request_context_getter->GetURLRequestContext()->GetNetworkSessionParams();
GetChannelIDOutput* output = new GetChannelIDOutput();
net::CompletionCallback net_completion_callback =
base::Bind(&MessagePropertyProvider::GotChannelID, original_task_runner,
base::Owned(output), reply);
if (!network_params->enable_channel_id) {
GotChannelID(original_task_runner, output, reply, net::ERR_FILE_NOT_FOUND);
return;
}
net::ChannelIDService* channel_id_service =
request_context_getter->GetURLRequestContext()->channel_id_service();
int status = channel_id_service->GetChannelID(
host, &output->channel_id_key, net_completion_callback, &output->request);
if (status == net::ERR_IO_PENDING)
return;
GotChannelID(original_task_runner, output, reply, status);
}
// static
void MessagePropertyProvider::GotChannelID(
scoped_refptr<base::TaskRunner> original_task_runner,
struct GetChannelIDOutput* output,
const ChannelIDCallback& reply,
int status) {
base::Closure no_tls_channel_id_closure = base::Bind(reply, "");
if (status != net::OK) {
original_task_runner->PostTask(FROM_HERE, no_tls_channel_id_closure);
return;
}
std::vector<uint8_t> spki_vector;
if (!output->channel_id_key->ExportPublicKey(&spki_vector)) {
original_task_runner->PostTask(FROM_HERE, no_tls_channel_id_closure);
return;
}
base::StringPiece spki(reinterpret_cast<char*>(spki_vector.data()),
spki_vector.size());
base::DictionaryValue jwk_value;
if (!net::JwkSerializer::ConvertSpkiFromDerToJwk(spki, &jwk_value)) {
original_task_runner->PostTask(FROM_HERE, no_tls_channel_id_closure);
return;
}
std::string jwk_str;
base::JSONWriter::Write(jwk_value, &jwk_str);
original_task_runner->PostTask(FROM_HERE, base::BindOnce(reply, jwk_str));
}
} // namespace extensions