• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/ssl/ssl_client_auth_handler.h"
6 
7 #include "chrome/browser/ssl/ssl_client_auth_notification_details.h"
8 #include "content/browser/browser_thread.h"
9 #include "content/browser/renderer_host/render_view_host_delegate.h"
10 #include "content/browser/renderer_host/render_view_host_notification_task.h"
11 #include "content/browser/renderer_host/resource_dispatcher_host.h"
12 #include "content/browser/renderer_host/resource_dispatcher_host_request_info.h"
13 #include "content/common/notification_service.h"
14 #include "net/url_request/url_request.h"
15 
SSLClientAuthHandler(net::URLRequest * request,net::SSLCertRequestInfo * cert_request_info)16 SSLClientAuthHandler::SSLClientAuthHandler(
17     net::URLRequest* request,
18     net::SSLCertRequestInfo* cert_request_info)
19     : request_(request),
20       cert_request_info_(cert_request_info) {
21 }
22 
~SSLClientAuthHandler()23 SSLClientAuthHandler::~SSLClientAuthHandler() {
24   // If we were simply dropped, then act as if we selected no certificate.
25   DoCertificateSelected(NULL);
26 }
27 
OnRequestCancelled()28 void SSLClientAuthHandler::OnRequestCancelled() {
29   request_ = NULL;
30 }
31 
SelectCertificate()32 void SSLClientAuthHandler::SelectCertificate() {
33   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
34 
35   int render_process_host_id;
36   int render_view_host_id;
37   if (!ResourceDispatcherHost::RenderViewForRequest(request_,
38                                                     &render_process_host_id,
39                                                     &render_view_host_id))
40     NOTREACHED();
41 
42   // If the RVH does not exist by the time this task gets run, then the task
43   // will be dropped and the scoped_refptr to SSLClientAuthHandler will go
44   // away, so we do not leak anything. The destructor takes care of ensuring
45   // the net::URLRequest always gets a response.
46   CallRenderViewHostSSLDelegate(
47       render_process_host_id, render_view_host_id,
48       &RenderViewHostDelegate::SSL::ShowClientCertificateRequestDialog,
49       scoped_refptr<SSLClientAuthHandler>(this));
50 }
51 
52 // Sends an SSL_CLIENT_AUTH_CERT_SELECTED notification and notifies the IO
53 // thread that we have selected a cert.
CertificateSelected(net::X509Certificate * cert)54 void SSLClientAuthHandler::CertificateSelected(net::X509Certificate* cert) {
55   VLOG(1) << this << " CertificateSelected " << cert;
56   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
57 
58   SSLClientAuthNotificationDetails details(cert_request_info_, cert);
59   NotificationService* service = NotificationService::current();
60   service->Notify(NotificationType::SSL_CLIENT_AUTH_CERT_SELECTED,
61                   Source<SSLClientAuthHandler>(this),
62                   Details<SSLClientAuthNotificationDetails>(&details));
63 
64   CertificateSelectedNoNotify(cert);
65 }
66 
67 // Notifies the IO thread that we have selected a cert.
CertificateSelectedNoNotify(net::X509Certificate * cert)68 void SSLClientAuthHandler::CertificateSelectedNoNotify(
69     net::X509Certificate* cert) {
70   VLOG(1) << this << " CertificateSelectedNoNotify " << cert;
71   BrowserThread::PostTask(
72       BrowserThread::IO, FROM_HERE,
73       NewRunnableMethod(
74           this, &SSLClientAuthHandler::DoCertificateSelected, cert));
75 }
76 
DoCertificateSelected(net::X509Certificate * cert)77 void SSLClientAuthHandler::DoCertificateSelected(net::X509Certificate* cert) {
78   VLOG(1) << this << " DoCertificateSelected " << cert;
79   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
80   // request_ could have been NULLed if the request was cancelled while the
81   // user was choosing a cert, or because we have already responded to the
82   // certificate.
83   if (request_) {
84     request_->ContinueWithCertificate(cert);
85 
86     ResourceDispatcherHostRequestInfo* info =
87         ResourceDispatcherHost::InfoForRequest(request_);
88     if (info)
89       info->set_ssl_client_auth_handler(NULL);
90 
91     request_ = NULL;
92   }
93 }
94 
SSLClientAuthObserver(net::SSLCertRequestInfo * cert_request_info,SSLClientAuthHandler * handler)95 SSLClientAuthObserver::SSLClientAuthObserver(
96     net::SSLCertRequestInfo* cert_request_info,
97     SSLClientAuthHandler* handler)
98     : cert_request_info_(cert_request_info), handler_(handler) {
99 }
100 
~SSLClientAuthObserver()101 SSLClientAuthObserver::~SSLClientAuthObserver() {
102   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
103 }
104 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)105 void SSLClientAuthObserver::Observe(
106     NotificationType type,
107     const NotificationSource& source,
108     const NotificationDetails& details) {
109   VLOG(1) << "SSLClientAuthObserver::Observe " << this << " " << handler_.get();
110   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
111   DCHECK(type == NotificationType::SSL_CLIENT_AUTH_CERT_SELECTED);
112 
113   if (Source<SSLClientAuthHandler>(source).ptr() == handler_.get()) {
114     VLOG(1) << "got notification from ourself " << handler_.get();
115     return;
116   }
117 
118   SSLClientAuthNotificationDetails* auth_details =
119       Details<SSLClientAuthNotificationDetails>(details).ptr();
120   if (!auth_details->IsSameHost(cert_request_info_))
121     return;
122 
123   VLOG(1) << this << " got matching notification for "
124           << handler_.get() << ", selecting cert "
125           << auth_details->selected_cert();
126   StopObserving();
127   handler_->CertificateSelectedNoNotify(auth_details->selected_cert());
128   OnCertSelectedByNotification();
129 }
130 
StartObserving()131 void SSLClientAuthObserver::StartObserving() {
132   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
133   notification_registrar_.Add(this,
134                               NotificationType::SSL_CLIENT_AUTH_CERT_SELECTED,
135                               NotificationService::AllSources());
136 }
137 
StopObserving()138 void SSLClientAuthObserver::StopObserving() {
139   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
140   notification_registrar_.RemoveAll();
141 }
142