Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Side by Side Diff: remoting/protocol/channel_authenticator.cc

Issue 8604001: Move SSL layer initialization into ChannelAuthenticator implementations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: - Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "remoting/protocol/channel_authenticator.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/string_piece.h"
9 #include "crypto/hmac.h"
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
12 #include "net/socket/ssl_socket.h"
13 #include "net/socket/stream_socket.h"
14
15 namespace remoting {
16 namespace protocol {
17
18 namespace {
19
20 // Labels for use when exporting the SSL master keys.
21 const char kClientSslExporterLabel[] = "EXPORTER-remoting-channel-auth-client";
22
23 // Size of the HMAC-SHA-256 authentication digest.
24 const size_t kAuthDigestLength = 32;
25
26 // static
27 bool GetAuthBytes(const std::string& shared_secret,
28 const std::string& key_material,
29 std::string* auth_bytes) {
30 // Generate auth digest based on the keying material and shared secret.
31 crypto::HMAC response(crypto::HMAC::SHA256);
32 if (!response.Init(key_material)) {
33 NOTREACHED() << "HMAC::Init failed";
34 return false;
35 }
36 unsigned char out_bytes[kAuthDigestLength];
37 if (!response.Sign(shared_secret, out_bytes, kAuthDigestLength)) {
38 NOTREACHED() << "HMAC::Sign failed";
39 return false;
40 }
41
42 auth_bytes->assign(out_bytes, out_bytes + kAuthDigestLength);
43 return true;
44 }
45
46 } // namespace
47
48 HostChannelAuthenticator::HostChannelAuthenticator(
49 const std::string& shared_secret)
50 : shared_secret_(shared_secret),
51 socket_(NULL),
52 ALLOW_THIS_IN_INITIALIZER_LIST(auth_read_callback_(
53 this, &HostChannelAuthenticator::OnAuthBytesRead)) {
54 }
55
56 HostChannelAuthenticator::~HostChannelAuthenticator() {
57 }
58
59 void HostChannelAuthenticator::Authenticate(net::SSLSocket* socket,
60 const DoneCallback& done_callback) {
61 DCHECK(CalledOnValidThread());
62
63 socket_ = socket;
64 done_callback_ = done_callback;
65
66 unsigned char key_material[kAuthDigestLength];
67 int result = socket_->ExportKeyingMaterial(
68 kClientSslExporterLabel, "", key_material, kAuthDigestLength);
69 if (result != net::OK) {
70 LOG(ERROR) << "Error fetching keying material: " << result;
71 done_callback.Run(FAILURE);
72 return;
73 }
74
75 if (!GetAuthBytes(shared_secret_,
76 std::string(key_material, key_material + kAuthDigestLength),
77 &auth_bytes_)) {
78 done_callback.Run(FAILURE);
79 return;
80 }
81
82 // Read an authentication digest.
83 auth_read_buf_ = new net::GrowableIOBuffer();
84 auth_read_buf_->SetCapacity(kAuthDigestLength);
85 DoAuthRead();
86 }
87
88 void HostChannelAuthenticator::DoAuthRead() {
89 while (true) {
90 int result = socket_->Read(auth_read_buf_,
91 auth_read_buf_->RemainingCapacity(),
92 &auth_read_callback_);
93 if (result == net::ERR_IO_PENDING)
94 break;
95 if (!HandleAuthBytesRead(result))
96 break;
97 }
98 }
99
100 void HostChannelAuthenticator::OnAuthBytesRead(int result) {
101 DCHECK(CalledOnValidThread());
102
103 if (HandleAuthBytesRead(result))
104 DoAuthRead();
105 }
106
107 bool HostChannelAuthenticator::HandleAuthBytesRead(int read_result) {
108 if (read_result <= 0) {
109 LOG(ERROR) << "Error reading authentication: " << read_result;
110 done_callback_.Run(FAILURE);
111 return false;
112 }
113
114 auth_read_buf_->set_offset(auth_read_buf_->offset() + read_result);
115 if (auth_read_buf_->RemainingCapacity() > 0)
116 return true;
117
118 if (!VerifyAuthBytes(std::string(
119 auth_read_buf_->StartOfBuffer(),
120 auth_read_buf_->StartOfBuffer() + kAuthDigestLength))) {
121 LOG(ERROR) << "Mismatched authentication";
122 done_callback_.Run(FAILURE);
123 return false;
124 }
125
126 done_callback_.Run(SUCCESS);
127 return false;
128 }
129
130 bool HostChannelAuthenticator::VerifyAuthBytes(
131 const std::string& received_auth_bytes) {
132 DCHECK(received_auth_bytes.length() == kAuthDigestLength);
133
134 // Compare the received and expected digests in fixed time, to limit the
135 // scope for timing attacks.
136 uint8 result = 0;
137 for (unsigned i = 0; i < auth_bytes_.length(); i++) {
138 result |= received_auth_bytes[i] ^ auth_bytes_[i];
139 }
140 return result == 0;
141 }
142
143 ClientChannelAuthenticator::ClientChannelAuthenticator(
144 const std::string& shared_secret)
145 : shared_secret_(shared_secret),
146 socket_(NULL),
147 ALLOW_THIS_IN_INITIALIZER_LIST(auth_write_callback_(
148 this, &ClientChannelAuthenticator::OnAuthBytesWritten)) {
149 }
150
151 ClientChannelAuthenticator::~ClientChannelAuthenticator() {
152 }
153
154 void ClientChannelAuthenticator::Authenticate(
155 net::SSLSocket* socket,
156 const DoneCallback& done_callback) {
157 DCHECK(CalledOnValidThread());
158
159 socket_ = socket;
160 done_callback_ = done_callback;
161
162 unsigned char key_material[kAuthDigestLength];
163 int result = socket_->ExportKeyingMaterial(
164 kClientSslExporterLabel, "", key_material, kAuthDigestLength);
165 if (result != net::OK) {
166 LOG(ERROR) << "Error fetching keying material: " << result;
167 done_callback.Run(FAILURE);
168 return;
169 }
170
171 std::string auth_bytes;
172 if (!GetAuthBytes(shared_secret_,
173 std::string(key_material, key_material + kAuthDigestLength),
174 &auth_bytes)) {
175 done_callback.Run(FAILURE);
176 return;
177 }
178
179 // Allocate a buffer to write the authentication digest.
180 auth_write_buf_ = new net::DrainableIOBuffer(
181 new net::StringIOBuffer(auth_bytes), auth_bytes.size());
182 DoAuthWrite();
183 }
184
185 void ClientChannelAuthenticator::DoAuthWrite() {
186 while (true) {
187 int result = socket_->Write(auth_write_buf_,
188 auth_write_buf_->BytesRemaining(),
189 &auth_write_callback_);
190 if (result == net::ERR_IO_PENDING)
191 break;
192 if (!HandleAuthBytesWritten(result))
193 break;
194 }
195 }
196
197 void ClientChannelAuthenticator::OnAuthBytesWritten(int result) {
198 DCHECK(CalledOnValidThread());
199
200 if (HandleAuthBytesWritten(result))
201 DoAuthWrite();
202 }
203
204 bool ClientChannelAuthenticator::HandleAuthBytesWritten(int result) {
205 if (result <= 0) {
206 LOG(ERROR) << "Error writing authentication: " << result;
207 done_callback_.Run(FAILURE);
208 return false;
209 }
210
211 auth_write_buf_->DidConsume(result);
212 if (auth_write_buf_->BytesRemaining() > 0)
213 return true;
214
215 done_callback_.Run(SUCCESS);
216 return false;
217 }
218
219 } // namespace protocol
220 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698