1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/extensions/api/messaging/message_property_provider.h" 6 7#include "base/json/json_writer.h" 8#include "base/logging.h" 9#include "base/message_loop/message_loop_proxy.h" 10#include "base/strings/string_piece.h" 11#include "base/values.h" 12#include "chrome/browser/profiles/profile.h" 13#include "content/public/browser/browser_thread.h" 14#include "extensions/common/api/runtime.h" 15#include "net/base/completion_callback.h" 16#include "net/cert/asn1_util.h" 17#include "net/cert/jwk_serializer.h" 18#include "net/ssl/channel_id_service.h" 19#include "net/url_request/url_request_context.h" 20#include "net/url_request/url_request_context_getter.h" 21#include "url/gurl.h" 22 23namespace extensions { 24 25MessagePropertyProvider::MessagePropertyProvider() {} 26 27void MessagePropertyProvider::GetChannelID(Profile* profile, 28 const GURL& source_url, const ChannelIDCallback& reply) { 29 if (!source_url.is_valid()) { 30 // This isn't a real URL, so there's no sense in looking for a channel ID 31 // for it. Dispatch with an empty tls channel ID. 32 reply.Run(std::string()); 33 return; 34 } 35 scoped_refptr<net::URLRequestContextGetter> request_context_getter( 36 profile->GetRequestContext()); 37 content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, 38 base::Bind(&MessagePropertyProvider::GetChannelIDOnIOThread, 39 base::MessageLoopProxy::current(), 40 request_context_getter, 41 source_url.host(), 42 reply)); 43} 44 45// Helper struct to bind the memory addresses that will be written to by 46// ChannelIDService::GetChannelID to the callback provided to 47// MessagePropertyProvider::GetChannelID. 48struct MessagePropertyProvider::GetChannelIDOutput { 49 std::string domain_bound_private_key; 50 std::string domain_bound_cert; 51 net::ChannelIDService::RequestHandle request_handle; 52}; 53 54// static 55void MessagePropertyProvider::GetChannelIDOnIOThread( 56 scoped_refptr<base::TaskRunner> original_task_runner, 57 scoped_refptr<net::URLRequestContextGetter> request_context_getter, 58 const std::string& host, 59 const ChannelIDCallback& reply) { 60 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); 61 net::ChannelIDService* channel_id_service = 62 request_context_getter->GetURLRequestContext()-> 63 channel_id_service(); 64 GetChannelIDOutput* output = new GetChannelIDOutput(); 65 net::CompletionCallback net_completion_callback = 66 base::Bind(&MessagePropertyProvider::GotChannelID, 67 original_task_runner, 68 base::Owned(output), 69 reply); 70 int status = channel_id_service->GetChannelID( 71 host, 72 &output->domain_bound_private_key, 73 &output->domain_bound_cert, 74 net_completion_callback, 75 &output->request_handle); 76 if (status == net::ERR_IO_PENDING) 77 return; 78 GotChannelID(original_task_runner, output, reply, status); 79} 80 81// static 82void MessagePropertyProvider::GotChannelID( 83 scoped_refptr<base::TaskRunner> original_task_runner, 84 struct GetChannelIDOutput* output, 85 const ChannelIDCallback& reply, 86 int status) { 87 base::Closure no_tls_channel_id_closure = base::Bind(reply, ""); 88 if (status != net::OK) { 89 original_task_runner->PostTask(FROM_HERE, no_tls_channel_id_closure); 90 return; 91 } 92 base::StringPiece spki; 93 if (!net::asn1::ExtractSPKIFromDERCert(output->domain_bound_cert, &spki)) { 94 original_task_runner->PostTask(FROM_HERE, no_tls_channel_id_closure); 95 return; 96 } 97 base::DictionaryValue jwk_value; 98 if (!net::JwkSerializer::ConvertSpkiFromDerToJwk(spki, &jwk_value)) { 99 original_task_runner->PostTask(FROM_HERE, no_tls_channel_id_closure); 100 return; 101 } 102 std::string jwk_str; 103 base::JSONWriter::Write(&jwk_value, &jwk_str); 104 original_task_runner->PostTask(FROM_HERE, base::Bind(reply, jwk_str)); 105} 106 107} // namespace extensions 108