blob: 85b00729c13ac886de8377add70984763c7fa4db [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 "chrome/browser/extensions/api/messaging/message_property_provider.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/string_piece.h"
#include "base/values.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/runtime.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/completion_callback.h"
#include "net/cert/asn1_util.h"
#include "net/cert/jwk_serializer.h"
#include "net/ssl/server_bound_cert_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::GetDomainBoundCert(Profile* profile,
const GURL& source_url, const DomainBoundCertCallback& 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;
}
scoped_refptr<net::URLRequestContextGetter> request_context_getter(
profile->GetRequestContext());
content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
base::Bind(&MessagePropertyProvider::GetDomainBoundCertOnIOThread,
base::MessageLoopProxy::current(),
request_context_getter,
source_url.host(),
reply));
}
// Helper struct to bind the memory addresses that will be written to by
// ServerBoundCertService::GetDomainBoundCert to the callback provided to
// MessagePropertyProvider::GetDomainBoundCert.
struct MessagePropertyProvider::GetDomainBoundCertOutput {
std::string domain_bound_private_key;
std::string domain_bound_cert;
net::ServerBoundCertService::RequestHandle request_handle;
};
// static
void MessagePropertyProvider::GetDomainBoundCertOnIOThread(
scoped_refptr<base::TaskRunner> original_task_runner,
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
const std::string& host,
const DomainBoundCertCallback& reply) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
net::ServerBoundCertService* server_bound_cert_service =
request_context_getter->GetURLRequestContext()->
server_bound_cert_service();
GetDomainBoundCertOutput* output = new GetDomainBoundCertOutput();
net::CompletionCallback net_completion_callback =
base::Bind(&MessagePropertyProvider::GotDomainBoundCert,
original_task_runner,
base::Owned(output),
reply);
int status = server_bound_cert_service->GetDomainBoundCert(
host,
&output->domain_bound_private_key,
&output->domain_bound_cert,
net_completion_callback,
&output->request_handle);
if (status == net::ERR_IO_PENDING)
return;
GotDomainBoundCert(original_task_runner, output, reply, status);
}
// static
void MessagePropertyProvider::GotDomainBoundCert(
scoped_refptr<base::TaskRunner> original_task_runner,
struct GetDomainBoundCertOutput* output,
const DomainBoundCertCallback& 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;
}
base::StringPiece spki;
if (!net::asn1::ExtractSPKIFromDERCert(output->domain_bound_cert, &spki)) {
original_task_runner->PostTask(FROM_HERE, no_tls_channel_id_closure);
return;
}
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::Bind(reply, jwk_str));
}
} // namespace extensions