Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / remoting / protocol / ssl_hmac_channel_authenticator.cc
blobd8385c3ffbe4dc07d90ec00aced3fc5d03cf1c81
1 // Copyright (c) 2012 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.
5 #include "remoting/protocol/ssl_hmac_channel_authenticator.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback_helpers.h"
10 #include "base/logging.h"
11 #include "crypto/secure_util.h"
12 #include "net/base/host_port_pair.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
15 #include "net/cert/cert_status_flags.h"
16 #include "net/cert/cert_verifier.h"
17 #include "net/cert/x509_certificate.h"
18 #include "net/http/transport_security_state.h"
19 #include "net/socket/client_socket_factory.h"
20 #include "net/socket/client_socket_handle.h"
21 #include "net/socket/ssl_client_socket.h"
22 #include "net/socket/ssl_client_socket_openssl.h"
23 #include "net/socket/ssl_server_socket.h"
24 #include "net/ssl/ssl_config_service.h"
25 #include "remoting/base/rsa_key_pair.h"
26 #include "remoting/protocol/auth_util.h"
28 namespace remoting {
29 namespace protocol {
31 namespace {
33 // A CertVerifier which rejects every certificate.
34 class FailingCertVerifier : public net::CertVerifier {
35 public:
36 FailingCertVerifier() {}
37 ~FailingCertVerifier() override {}
39 int Verify(net::X509Certificate* cert,
40 const std::string& hostname,
41 const std::string& ocsp_response,
42 int flags,
43 net::CRLSet* crl_set,
44 net::CertVerifyResult* verify_result,
45 const net::CompletionCallback& callback,
46 RequestHandle* out_req,
47 const net::BoundNetLog& net_log) override {
48 verify_result->verified_cert = cert;
49 verify_result->cert_status = net::CERT_STATUS_INVALID;
50 return net::ERR_CERT_INVALID;
53 void CancelRequest(RequestHandle req) override {
54 NOTIMPLEMENTED();
58 } // namespace
60 // static
61 scoped_ptr<SslHmacChannelAuthenticator>
62 SslHmacChannelAuthenticator::CreateForClient(
63 const std::string& remote_cert,
64 const std::string& auth_key) {
65 scoped_ptr<SslHmacChannelAuthenticator> result(
66 new SslHmacChannelAuthenticator(auth_key));
67 result->remote_cert_ = remote_cert;
68 return result.Pass();
71 scoped_ptr<SslHmacChannelAuthenticator>
72 SslHmacChannelAuthenticator::CreateForHost(
73 const std::string& local_cert,
74 scoped_refptr<RsaKeyPair> key_pair,
75 const std::string& auth_key) {
76 scoped_ptr<SslHmacChannelAuthenticator> result(
77 new SslHmacChannelAuthenticator(auth_key));
78 result->local_cert_ = local_cert;
79 result->local_key_pair_ = key_pair;
80 return result.Pass();
83 SslHmacChannelAuthenticator::SslHmacChannelAuthenticator(
84 const std::string& auth_key)
85 : auth_key_(auth_key) {
88 SslHmacChannelAuthenticator::~SslHmacChannelAuthenticator() {
91 void SslHmacChannelAuthenticator::SecureAndAuthenticate(
92 scoped_ptr<net::StreamSocket> socket, const DoneCallback& done_callback) {
93 DCHECK(CalledOnValidThread());
94 DCHECK(socket->IsConnected());
96 done_callback_ = done_callback;
98 int result;
99 if (is_ssl_server()) {
100 #if defined(OS_NACL)
101 // Client plugin doesn't use server SSL sockets, and so SSLServerSocket
102 // implementation is not compiled for NaCl as part of net_nacl.
103 NOTREACHED();
104 result = net::ERR_FAILED;
105 #else
106 scoped_refptr<net::X509Certificate> cert =
107 net::X509Certificate::CreateFromBytes(
108 local_cert_.data(), local_cert_.length());
109 if (!cert.get()) {
110 LOG(ERROR) << "Failed to parse X509Certificate";
111 NotifyError(net::ERR_FAILED);
112 return;
115 net::SSLConfig ssl_config;
116 ssl_config.require_forward_secrecy = true;
118 scoped_ptr<net::SSLServerSocket> server_socket =
119 net::CreateSSLServerSocket(socket.Pass(),
120 cert.get(),
121 local_key_pair_->private_key(),
122 ssl_config);
123 net::SSLServerSocket* raw_server_socket = server_socket.get();
124 socket_ = server_socket.Pass();
125 result = raw_server_socket->Handshake(
126 base::Bind(&SslHmacChannelAuthenticator::OnConnected,
127 base::Unretained(this)));
128 #endif
129 } else {
130 transport_security_state_.reset(new net::TransportSecurityState);
131 cert_verifier_.reset(new FailingCertVerifier);
133 net::SSLConfig::CertAndStatus cert_and_status;
134 cert_and_status.cert_status = net::CERT_STATUS_AUTHORITY_INVALID;
135 cert_and_status.der_cert = remote_cert_;
137 net::SSLConfig ssl_config;
138 // Certificate verification and revocation checking are not needed
139 // because we use self-signed certs. Disable it so that the SSL
140 // layer doesn't try to initialize OCSP (OCSP works only on the IO
141 // thread).
142 ssl_config.cert_io_enabled = false;
143 ssl_config.rev_checking_enabled = false;
144 ssl_config.allowed_bad_certs.push_back(cert_and_status);
146 net::HostPortPair host_and_port(kSslFakeHostName, 0);
147 net::SSLClientSocketContext context;
148 context.transport_security_state = transport_security_state_.get();
149 context.cert_verifier = cert_verifier_.get();
150 scoped_ptr<net::ClientSocketHandle> socket_handle(
151 new net::ClientSocketHandle);
152 socket_handle->SetSocket(socket.Pass());
154 #if defined(OS_NACL)
155 // net_nacl doesn't include ClientSocketFactory.
156 socket_.reset(new net::SSLClientSocketOpenSSL(
157 socket_handle.Pass(), host_and_port, ssl_config, context));
158 #else
159 socket_ =
160 net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
161 socket_handle.Pass(), host_and_port, ssl_config, context);
162 #endif
164 result = socket_->Connect(
165 base::Bind(&SslHmacChannelAuthenticator::OnConnected,
166 base::Unretained(this)));
169 if (result == net::ERR_IO_PENDING)
170 return;
172 OnConnected(result);
175 bool SslHmacChannelAuthenticator::is_ssl_server() {
176 return local_key_pair_.get() != nullptr;
179 void SslHmacChannelAuthenticator::OnConnected(int result) {
180 if (result != net::OK) {
181 LOG(WARNING) << "Failed to establish SSL connection";
182 NotifyError(result);
183 return;
186 // Generate authentication digest to write to the socket.
187 std::string auth_bytes = GetAuthBytes(
188 socket_.get(), is_ssl_server() ?
189 kHostAuthSslExporterLabel : kClientAuthSslExporterLabel, auth_key_);
190 if (auth_bytes.empty()) {
191 NotifyError(net::ERR_FAILED);
192 return;
195 // Allocate a buffer to write the digest.
196 auth_write_buf_ = new net::DrainableIOBuffer(
197 new net::StringIOBuffer(auth_bytes), auth_bytes.size());
199 // Read an incoming token.
200 auth_read_buf_ = new net::GrowableIOBuffer();
201 auth_read_buf_->SetCapacity(kAuthDigestLength);
203 // If WriteAuthenticationBytes() results in |done_callback_| being
204 // called then we must not do anything else because this object may
205 // be destroyed at that point.
206 bool callback_called = false;
207 WriteAuthenticationBytes(&callback_called);
208 if (!callback_called)
209 ReadAuthenticationBytes();
212 void SslHmacChannelAuthenticator::WriteAuthenticationBytes(
213 bool* callback_called) {
214 while (true) {
215 int result = socket_->Write(
216 auth_write_buf_.get(),
217 auth_write_buf_->BytesRemaining(),
218 base::Bind(&SslHmacChannelAuthenticator::OnAuthBytesWritten,
219 base::Unretained(this)));
220 if (result == net::ERR_IO_PENDING)
221 break;
222 if (!HandleAuthBytesWritten(result, callback_called))
223 break;
227 void SslHmacChannelAuthenticator::OnAuthBytesWritten(int result) {
228 DCHECK(CalledOnValidThread());
230 if (HandleAuthBytesWritten(result, nullptr))
231 WriteAuthenticationBytes(nullptr);
234 bool SslHmacChannelAuthenticator::HandleAuthBytesWritten(
235 int result, bool* callback_called) {
236 if (result <= 0) {
237 LOG(ERROR) << "Error writing authentication: " << result;
238 if (callback_called)
239 *callback_called = false;
240 NotifyError(result);
241 return false;
244 auth_write_buf_->DidConsume(result);
245 if (auth_write_buf_->BytesRemaining() > 0)
246 return true;
248 auth_write_buf_ = nullptr;
249 CheckDone(callback_called);
250 return false;
253 void SslHmacChannelAuthenticator::ReadAuthenticationBytes() {
254 while (true) {
255 int result =
256 socket_->Read(auth_read_buf_.get(),
257 auth_read_buf_->RemainingCapacity(),
258 base::Bind(&SslHmacChannelAuthenticator::OnAuthBytesRead,
259 base::Unretained(this)));
260 if (result == net::ERR_IO_PENDING)
261 break;
262 if (!HandleAuthBytesRead(result))
263 break;
267 void SslHmacChannelAuthenticator::OnAuthBytesRead(int result) {
268 DCHECK(CalledOnValidThread());
270 if (HandleAuthBytesRead(result))
271 ReadAuthenticationBytes();
274 bool SslHmacChannelAuthenticator::HandleAuthBytesRead(int read_result) {
275 if (read_result <= 0) {
276 NotifyError(read_result);
277 return false;
280 auth_read_buf_->set_offset(auth_read_buf_->offset() + read_result);
281 if (auth_read_buf_->RemainingCapacity() > 0)
282 return true;
284 if (!VerifyAuthBytes(std::string(
285 auth_read_buf_->StartOfBuffer(),
286 auth_read_buf_->StartOfBuffer() + kAuthDigestLength))) {
287 LOG(WARNING) << "Mismatched authentication";
288 NotifyError(net::ERR_FAILED);
289 return false;
292 auth_read_buf_ = nullptr;
293 CheckDone(nullptr);
294 return false;
297 bool SslHmacChannelAuthenticator::VerifyAuthBytes(
298 const std::string& received_auth_bytes) {
299 DCHECK(received_auth_bytes.length() == kAuthDigestLength);
301 // Compute expected auth bytes.
302 std::string auth_bytes = GetAuthBytes(
303 socket_.get(), is_ssl_server() ?
304 kClientAuthSslExporterLabel : kHostAuthSslExporterLabel, auth_key_);
305 if (auth_bytes.empty())
306 return false;
308 return crypto::SecureMemEqual(received_auth_bytes.data(),
309 &(auth_bytes[0]), kAuthDigestLength);
312 void SslHmacChannelAuthenticator::CheckDone(bool* callback_called) {
313 if (auth_write_buf_.get() == nullptr && auth_read_buf_.get() == nullptr) {
314 DCHECK(socket_.get() != nullptr);
315 if (callback_called)
316 *callback_called = true;
318 base::ResetAndReturn(&done_callback_).Run(net::OK, socket_.Pass());
322 void SslHmacChannelAuthenticator::NotifyError(int error) {
323 base::ResetAndReturn(&done_callback_).Run(error, nullptr);
326 } // namespace protocol
327 } // namespace remoting