14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/extensions/api/messaging/message_property_provider.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/json/json_writer.h"
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/logging.h"
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/strings/string_piece.h"
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/values.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "extensions/common/api/runtime.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/base/completion_callback.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/cert/asn1_util.h"
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/cert/jwk_serializer.h"
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/ssl/channel_id_service.h"
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/url_request/url_request_context.h"
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "url/gurl.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace extensions {
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)MessagePropertyProvider::MessagePropertyProvider() {}
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void MessagePropertyProvider::GetChannelID(Profile* profile,
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const GURL& source_url, const ChannelIDCallback& reply) {
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!source_url.is_valid()) {
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // This isn't a real URL, so there's no sense in looking for a channel ID
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // for it. Dispatch with an empty tls channel ID.
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    reply.Run(std::string());
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_refptr<net::URLRequestContextGetter> request_context_getter(
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      profile->GetRequestContext());
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&MessagePropertyProvider::GetChannelIDOnIOThread,
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 base::MessageLoopProxy::current(),
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 request_context_getter,
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 source_url.host(),
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 reply));
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Helper struct to bind the memory addresses that will be written to by
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// ChannelIDService::GetChannelID to the callback provided to
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// MessagePropertyProvider::GetChannelID.
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)struct MessagePropertyProvider::GetChannelIDOutput {
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string domain_bound_private_key;
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string domain_bound_cert;
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  net::ChannelIDService::RequestHandle request_handle;
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void MessagePropertyProvider::GetChannelIDOnIOThread(
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    scoped_refptr<base::TaskRunner> original_task_runner,
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& host,
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const ChannelIDCallback& reply) {
60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  net::ChannelIDService* channel_id_service =
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      request_context_getter->GetURLRequestContext()->
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          channel_id_service();
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  GetChannelIDOutput* output = new GetChannelIDOutput();
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  net::CompletionCallback net_completion_callback =
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&MessagePropertyProvider::GotChannelID,
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 original_task_runner,
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 base::Owned(output),
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 reply);
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int status = channel_id_service->GetChannelID(
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      host,
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      &output->domain_bound_private_key,
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      &output->domain_bound_cert,
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      net_completion_callback,
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      &output->request_handle);
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (status == net::ERR_IO_PENDING)
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  GotChannelID(original_task_runner, output, reply, status);
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void MessagePropertyProvider::GotChannelID(
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    scoped_refptr<base::TaskRunner> original_task_runner,
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    struct GetChannelIDOutput* output,
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const ChannelIDCallback& reply,
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    int status) {
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::Closure no_tls_channel_id_closure = base::Bind(reply, "");
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (status != net::OK) {
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    original_task_runner->PostTask(FROM_HERE, no_tls_channel_id_closure);
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::StringPiece spki;
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!net::asn1::ExtractSPKIFromDERCert(output->domain_bound_cert, &spki)) {
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    original_task_runner->PostTask(FROM_HERE, no_tls_channel_id_closure);
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::DictionaryValue jwk_value;
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!net::JwkSerializer::ConvertSpkiFromDerToJwk(spki, &jwk_value)) {
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    original_task_runner->PostTask(FROM_HERE, no_tls_channel_id_closure);
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string jwk_str;
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::JSONWriter::Write(&jwk_value, &jwk_str);
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  original_task_runner->PostTask(FROM_HERE, base::Bind(reply, jwk_str));
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace extensions
108