OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2010 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 "net/socket/ssl_server_socket_nss.h" | |
6 | |
7 #if defined(USE_SYSTEM_SSL) | |
8 #include <dlfcn.h> | |
9 #endif | |
10 #if defined(OS_MACOSX) | |
11 #include <Security/Security.h> | |
12 #endif | |
13 #include <certdb.h> | |
14 #include <cryptohi.h> | |
15 #include <hasht.h> | |
16 #include <keyhi.h> | |
17 #include <nspr.h> | |
18 #include <nss.h> | |
19 #include <pk11pub.h> | |
20 #include <secerr.h> | |
21 #include <sechash.h> | |
22 #include <ssl.h> | |
23 #include <sslerr.h> | |
24 #include <sslproto.h> | |
25 | |
26 #include <limits> | |
27 | |
28 #include "base/crypto/rsa_private_key.h" | |
29 #include "base/ref_counted.h" | |
30 #include "net/base/io_buffer.h" | |
31 #include "net/base/net_errors.h" | |
32 #include "net/base/net_log.h" | |
33 #include "net/ocsp/nss_ocsp.h" | |
34 #include "net/socket/nss_ssl_util.h" | |
35 #include "net/socket/ssl_error_params.h" | |
36 | |
37 static const int kRecvBufferSize = 4096; | |
38 | |
39 #define GotoState(s) next_handshake_state_ = s | |
40 | |
41 namespace net { | |
42 | |
43 SSLServerSocket* CreateSSLServerSocket( | |
44 Socket* socket, X509Certificate* cert, base::RSAPrivateKey* key) { | |
45 // SSLConfig is currently not used in SSLServerSocketNSS so pass in the | |
agl
2010/12/17 18:30:50
s/so/so we/
| |
46 // default object. | |
wtc
2010/12/17 18:08:04
API DESIGN: it's better to change CreateSSLServerS
Alpha Left Google
2010/12/17 20:31:12
Done.
| |
47 return new SSLServerSocketNSS(socket, SSLConfig(), cert, key); | |
48 } | |
49 | |
50 SSLServerSocketNSS::SSLServerSocketNSS( | |
51 Socket* socket, | |
wtc
2010/12/17 18:08:04
Nit: socket => transport_socket
Alpha Left Google
2010/12/17 20:31:12
Done.
| |
52 const SSLConfig& ssl_config, | |
wtc
2010/12/17 18:08:04
Nit: list ssl_config after cert and key.
Alpha Left Google
2010/12/17 20:31:12
Done.
Alpha Left Google
2010/12/17 20:31:12
Done.
| |
53 scoped_refptr<X509Certificate> cert, | |
54 base::RSAPrivateKey* key) | |
55 : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_( | |
56 this, &SSLServerSocketNSS::BufferSendComplete)), | |
57 ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_( | |
58 this, &SSLServerSocketNSS::BufferRecvComplete)), | |
59 transport_send_busy_(false), | |
60 transport_recv_busy_(false), | |
61 user_accept_callback_(NULL), | |
62 user_read_callback_(NULL), | |
63 user_write_callback_(NULL), | |
64 nss_fd_(NULL), | |
65 nss_bufs_(NULL), | |
66 transport_socket_(socket), | |
67 ssl_config_(ssl_config), | |
68 cert_(cert), | |
69 next_handshake_state_(STATE_NONE), | |
70 completed_handshake_(false) { | |
71 ssl_config_.false_start_enabled = false; | |
72 ssl_config_.ssl3_enabled = true; | |
73 ssl_config_.tls1_enabled = true; | |
74 | |
75 // TODO(hclam): Need a better way to clone a key. | |
76 std::vector<uint8> key_bytes; | |
77 CHECK(key->ExportPrivateKey(&key_bytes)); | |
78 key_.reset(base::RSAPrivateKey::CreateFromPrivateKeyInfo(key_bytes)); | |
79 CHECK(key_.get()); | |
80 } | |
81 | |
82 int SSLServerSocketNSS::Init() { | |
83 // Initialize the NSS SSL library in a threadsafe way. This also | |
84 // initializes the NSS base library. | |
85 EnsureNSSSSLInit(); | |
86 if (!NSS_IsInitialized()) | |
87 return ERR_UNEXPECTED; | |
88 #if !defined(OS_MACOSX) && !defined(OS_WIN) | |
89 // We must call EnsureOCSPInit() here, on the IO thread, to get the IO loop | |
90 // by MessageLoopForIO::current(). | |
91 // X509Certificate::Verify() runs on a worker thread of CertVerifier. | |
92 EnsureOCSPInit(); | |
93 #endif | |
94 | |
95 return OK; | |
96 } | |
97 | |
98 int SSLServerSocketNSS::Accept(CompletionCallback* callback) { | |
99 net_log_.BeginEvent(NetLog::TYPE_SSL_ACCEPT, NULL); | |
100 | |
101 int rv = Init(); | |
102 if (rv != OK) { | |
103 LOG(ERROR) << "Failed to initialize NSS"; | |
104 net_log_.EndEvent(NetLog::TYPE_SSL_ACCEPT, NULL); | |
105 return rv; | |
106 } | |
107 | |
108 rv = InitializeSSLOptions(); | |
109 if (rv != OK) { | |
110 LOG(ERROR) << "Failed to initialize SSL options"; | |
111 net_log_.EndEvent(NetLog::TYPE_SSL_ACCEPT, NULL); | |
112 return rv; | |
113 } | |
114 | |
115 // Set peer address. TODO(hclam): This should be in a separate method. | |
116 PRNetAddr peername; | |
117 memset(&peername, 0, sizeof(peername)); | |
118 peername.raw.family = AF_INET; | |
119 memio_SetPeerName(nss_fd_, &peername); | |
120 | |
121 GotoState(STATE_HANDSHAKE); | |
122 rv = DoHandshakeLoop(net::OK); | |
123 if (rv == ERR_IO_PENDING) { | |
124 user_accept_callback_ = callback; | |
125 } else { | |
126 net_log_.EndEvent(NetLog::TYPE_SSL_ACCEPT, NULL); | |
127 } | |
128 | |
129 return rv > OK ? OK : rv; | |
130 } | |
131 | |
132 int SSLServerSocketNSS::Read(IOBuffer* buf, int buf_len, | |
133 CompletionCallback* callback) { | |
134 DCHECK(!user_read_callback_); | |
135 DCHECK(!user_accept_callback_); | |
136 DCHECK(!user_read_buf_); | |
137 DCHECK(nss_bufs_); | |
138 | |
139 user_read_buf_ = buf; | |
140 user_read_buf_len_ = buf_len; | |
141 | |
142 DCHECK(completed_handshake_); | |
143 | |
144 int rv = DoReadLoop(OK); | |
145 | |
146 if (rv == ERR_IO_PENDING) { | |
147 user_read_callback_ = callback; | |
148 } else { | |
149 user_read_buf_ = NULL; | |
150 user_read_buf_len_ = 0; | |
151 } | |
152 return rv; | |
153 } | |
154 | |
155 int SSLServerSocketNSS::Write(IOBuffer* buf, int buf_len, | |
156 CompletionCallback* callback) { | |
157 DCHECK(!user_write_callback_); | |
158 DCHECK(!user_write_buf_); | |
159 DCHECK(nss_bufs_); | |
160 | |
161 user_write_buf_ = buf; | |
162 user_write_buf_len_ = buf_len; | |
163 | |
164 int rv = DoWriteLoop(OK); | |
165 | |
166 if (rv == ERR_IO_PENDING) { | |
167 user_write_callback_ = callback; | |
168 } else { | |
169 user_write_buf_ = NULL; | |
170 user_write_buf_len_ = 0; | |
171 } | |
172 return rv; | |
173 } | |
174 | |
175 // static | |
176 // NSS calls this if an incoming certificate needs to be verified. | |
177 // Do nothing but return SECSuccess. | |
178 // This is called only in full handshake mode. | |
179 // Peer certificate is retrieved in HandshakeCallback() later, which is called | |
180 // in full handshake mode or in resumption handshake mode. | |
181 SECStatus SSLServerSocketNSS::OwnAuthCertHandler(void* arg, | |
182 PRFileDesc* socket, | |
183 PRBool checksig, | |
184 PRBool is_server) { | |
185 // TODO(hclam): Implement. | |
186 // Tell NSS to not verify the certificate. | |
187 return SECSuccess; | |
188 } | |
189 | |
190 // static | |
191 // NSS calls this when handshake is completed. | |
192 // After the SSL handshake is finished we need to verify the certificate. | |
193 void SSLServerSocketNSS::HandshakeCallback(PRFileDesc* socket, | |
194 void* arg) { | |
195 // TODO(hclam): Implement. | |
196 } | |
197 | |
198 int SSLServerSocketNSS::InitializeSSLOptions() { | |
199 // Transport connected, now hook it up to nss | |
200 // TODO(port): specify rx and tx buffer sizes separately | |
201 nss_fd_ = memio_CreateIOLayer(kRecvBufferSize); | |
202 if (nss_fd_ == NULL) { | |
203 return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR error code. | |
204 } | |
205 | |
206 // Grab pointer to buffers | |
207 nss_bufs_ = memio_GetSecret(nss_fd_); | |
208 | |
209 /* Create SSL state machine */ | |
210 /* Push SSL onto our fake I/O socket */ | |
211 nss_fd_ = SSL_ImportFD(NULL, nss_fd_); | |
212 if (nss_fd_ == NULL) { | |
213 LogFailedNSSFunction(net_log_, "SSL_ImportFD", ""); | |
214 return ERR_OUT_OF_MEMORY; // TODO(port): map NSPR/NSS error code. | |
215 } | |
216 // TODO(port): set more ssl options! Check errors! | |
217 | |
218 int rv; | |
219 | |
220 rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE); | |
221 if (rv != SECSuccess) { | |
222 LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_SECURITY"); | |
223 return ERR_UNEXPECTED; | |
224 } | |
225 | |
226 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, PR_FALSE); | |
227 if (rv != SECSuccess) { | |
228 LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_SSL2"); | |
229 return ERR_UNEXPECTED; | |
230 } | |
231 | |
232 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, PR_TRUE); | |
233 if (rv != SECSuccess) { | |
234 LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_SSL3"); | |
235 return ERR_UNEXPECTED; | |
236 } | |
237 | |
238 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_TLS, ssl_config_.tls1_enabled); | |
239 if (rv != SECSuccess) { | |
240 LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_TLS"); | |
241 return ERR_UNEXPECTED; | |
242 } | |
243 | |
244 for (std::vector<uint16>::const_iterator it = | |
245 ssl_config_.disabled_cipher_suites.begin(); | |
246 it != ssl_config_.disabled_cipher_suites.end(); ++it) { | |
247 // This will fail if the specified cipher is not implemented by NSS, but | |
248 // the failure is harmless. | |
249 SSL_CipherPrefSet(nss_fd_, *it, PR_FALSE); | |
250 } | |
251 | |
252 // Server socket doesn't need session tickets. | |
253 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_FALSE); | |
254 if (rv != SECSuccess) { | |
255 LogFailedNSSFunction( | |
256 net_log_, "SSL_OptionSet", "SSL_ENABLE_SESSION_TICKETS"); | |
257 } | |
258 | |
259 // Doing this will force PR_Accept perform handshake as server. | |
260 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_FALSE); | |
261 if (rv != SECSuccess) { | |
262 LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_HANDSHAKE_AS_CLIENT"); | |
263 return ERR_UNEXPECTED; | |
264 } | |
265 | |
266 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_SERVER, PR_TRUE); | |
267 if (rv != SECSuccess) { | |
268 LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_HANDSHAKE_AS_SERVER"); | |
269 return ERR_UNEXPECTED; | |
270 } | |
271 | |
272 rv = SSL_OptionSet(nss_fd_, SSL_REQUEST_CERTIFICATE, PR_FALSE); | |
273 if (rv != SECSuccess) { | |
274 LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_REQUEST_CERTIFICATE"); | |
275 return ERR_UNEXPECTED; | |
276 } | |
277 | |
278 rv = SSL_OptionSet(nss_fd_, SSL_REQUIRE_CERTIFICATE, PR_FALSE); | |
279 if (rv != SECSuccess) { | |
280 LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_REQUIRE_CERTIFICATE"); | |
281 return ERR_UNEXPECTED; | |
282 } | |
283 | |
284 rv = SSL_OptionSet(nss_fd_, SSL_NO_CACHE, PR_TRUE); | |
285 if (rv != SECSuccess) { | |
286 LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_NO_CACHE"); | |
287 return ERR_UNEXPECTED; | |
288 } | |
289 | |
290 rv = SSL_AuthCertificateHook(nss_fd_, OwnAuthCertHandler, this); | |
291 if (rv != SECSuccess) { | |
292 LogFailedNSSFunction(net_log_, "SSL_AuthCertificateHook", ""); | |
293 return ERR_UNEXPECTED; | |
294 } | |
295 | |
296 rv = SSL_HandshakeCallback(nss_fd_, HandshakeCallback, this); | |
297 if (rv != SECSuccess) { | |
298 LogFailedNSSFunction(net_log_, "SSL_HandshakeCallback", ""); | |
299 return ERR_UNEXPECTED; | |
300 } | |
301 | |
302 // Assign server certificate and private key. | |
303 SSLKEAType cert_kea = NSS_FindCertKEAType(cert_->os_cert_handle()); | |
304 rv = SSL_ConfigSecureServer(nss_fd_, cert_->os_cert_handle(), | |
305 key_->key(), cert_kea); | |
306 if (rv != SECSuccess) { | |
307 PRErrorCode prerr = PR_GetError(); | |
308 LOG(ERROR) << "Failed to config SSL server: " << prerr; | |
309 LogFailedNSSFunction(net_log_, "SSL_ConfigureSecureServer", ""); | |
310 return ERR_UNEXPECTED; | |
311 } | |
312 | |
313 // Tell SSL we're a server; needed if not letting NSPR do socket I/O | |
314 rv = SSL_ResetHandshake(nss_fd_, PR_TRUE); | |
315 if (rv != SECSuccess) { | |
316 LogFailedNSSFunction(net_log_, "SSL_ResetHandshake", ""); | |
317 return ERR_UNEXPECTED; | |
318 } | |
319 | |
320 return OK; | |
321 } | |
322 | |
323 // Return 0 for EOF, | |
324 // > 0 for bytes transferred immediately, | |
325 // < 0 for error (or the non-error ERR_IO_PENDING). | |
326 int SSLServerSocketNSS::BufferSend(void) { | |
327 if (transport_send_busy_) | |
328 return ERR_IO_PENDING; | |
329 | |
330 const char* buf1; | |
331 const char* buf2; | |
332 unsigned int len1, len2; | |
333 memio_GetWriteParams(nss_bufs_, &buf1, &len1, &buf2, &len2); | |
334 const unsigned int len = len1 + len2; | |
335 | |
336 int rv = 0; | |
337 if (len) { | |
338 scoped_refptr<IOBuffer> send_buffer(new IOBuffer(len)); | |
339 memcpy(send_buffer->data(), buf1, len1); | |
340 memcpy(send_buffer->data() + len1, buf2, len2); | |
341 rv = transport_socket_->Write(send_buffer, len, | |
342 &buffer_send_callback_); | |
343 if (rv == ERR_IO_PENDING) { | |
344 transport_send_busy_ = true; | |
345 } else { | |
346 memio_PutWriteResult(nss_bufs_, MapErrorToNSS(rv)); | |
347 } | |
348 } | |
349 | |
350 return rv; | |
351 } | |
352 | |
353 void SSLServerSocketNSS::BufferSendComplete(int result) { | |
354 memio_PutWriteResult(nss_bufs_, MapErrorToNSS(result)); | |
355 transport_send_busy_ = false; | |
356 OnSendComplete(result); | |
357 } | |
358 | |
359 int SSLServerSocketNSS::BufferRecv(void) { | |
360 if (transport_recv_busy_) return ERR_IO_PENDING; | |
361 | |
362 char *buf; | |
363 int nb = memio_GetReadParams(nss_bufs_, &buf); | |
364 int rv; | |
365 if (!nb) { | |
366 // buffer too full to read into, so no I/O possible at moment | |
367 rv = ERR_IO_PENDING; | |
368 } else { | |
369 recv_buffer_ = new IOBuffer(nb); | |
370 rv = transport_socket_->Read(recv_buffer_, nb, &buffer_recv_callback_); | |
371 if (rv == ERR_IO_PENDING) { | |
372 transport_recv_busy_ = true; | |
373 } else { | |
374 if (rv > 0) | |
375 memcpy(buf, recv_buffer_->data(), rv); | |
376 memio_PutReadResult(nss_bufs_, MapErrorToNSS(rv)); | |
377 recv_buffer_ = NULL; | |
378 } | |
379 } | |
380 return rv; | |
381 } | |
382 | |
383 void SSLServerSocketNSS::BufferRecvComplete(int result) { | |
384 if (result > 0) { | |
385 char *buf; | |
386 memio_GetReadParams(nss_bufs_, &buf); | |
387 memcpy(buf, recv_buffer_->data(), result); | |
388 } | |
389 recv_buffer_ = NULL; | |
390 memio_PutReadResult(nss_bufs_, MapErrorToNSS(result)); | |
391 transport_recv_busy_ = false; | |
392 OnRecvComplete(result); | |
393 } | |
394 | |
395 void SSLServerSocketNSS::OnSendComplete(int result) { | |
wtc
2010/12/17 18:08:04
IMPORTANT: I believe OnSendComplete can be written
Alpha Left Google
2010/12/17 20:31:12
Done.
| |
396 if (next_handshake_state_ == STATE_HANDSHAKE) { | |
397 // In handshake phase. | |
398 OnHandshakeIOComplete(result); | |
399 return; | |
400 } | |
401 | |
402 int rv_write = ERR_IO_PENDING; | |
403 bool network_moved; | |
404 do { | |
405 if (user_write_buf_) | |
406 rv_write = DoPayloadWrite(); | |
407 network_moved = DoTransportIO(); | |
408 } while (rv_write == ERR_IO_PENDING && network_moved); | |
409 | |
410 if (user_write_buf_ && rv_write != ERR_IO_PENDING) | |
411 DoWriteCallback(rv_write); | |
412 } | |
413 | |
414 void SSLServerSocketNSS::OnRecvComplete(int result) { | |
415 if (next_handshake_state_ == STATE_HANDSHAKE) { | |
416 // In handshake phase. | |
417 OnHandshakeIOComplete(result); | |
418 return; | |
419 } | |
420 | |
421 // Network layer received some data, check if client requested to read | |
422 // decrypted data. | |
423 if (!user_read_buf_ || !completed_handshake_) { | |
424 return; | |
425 } | |
426 | |
427 int rv = DoReadLoop(result); | |
428 if (rv != ERR_IO_PENDING) | |
429 DoReadCallback(rv); | |
430 } | |
431 | |
432 void SSLServerSocketNSS::OnHandshakeIOComplete(int result) { | |
433 int rv = DoHandshakeLoop(result); | |
434 if (rv != ERR_IO_PENDING) { | |
435 net_log_.EndEvent(net::NetLog::TYPE_SSL_ACCEPT, NULL); | |
436 if (user_accept_callback_) | |
437 DoAcceptCallback(rv); | |
438 } | |
439 } | |
440 | |
441 void SSLServerSocketNSS::DoAcceptCallback(int rv) { | |
442 DCHECK_NE(rv, ERR_IO_PENDING); | |
443 | |
444 CompletionCallback* c = user_accept_callback_; | |
445 user_accept_callback_ = NULL; | |
446 c->Run(rv > OK ? OK : rv); | |
447 } | |
448 | |
449 void SSLServerSocketNSS::DoReadCallback(int rv) { | |
450 DCHECK(rv != ERR_IO_PENDING); | |
451 DCHECK(user_read_callback_); | |
452 | |
453 // Since Run may result in Read being called, clear |user_read_callback_| | |
454 // up front. | |
455 CompletionCallback* c = user_read_callback_; | |
456 user_read_callback_ = NULL; | |
457 user_read_buf_ = NULL; | |
458 user_read_buf_len_ = 0; | |
459 c->Run(rv); | |
460 } | |
461 | |
462 void SSLServerSocketNSS::DoWriteCallback(int rv) { | |
463 DCHECK(rv != ERR_IO_PENDING); | |
464 DCHECK(user_write_callback_); | |
465 | |
466 // Since Run may result in Write being called, clear |user_write_callback_| | |
467 // up front. | |
468 CompletionCallback* c = user_write_callback_; | |
469 user_write_callback_ = NULL; | |
470 user_write_buf_ = NULL; | |
471 user_write_buf_len_ = 0; | |
472 c->Run(rv); | |
473 } | |
474 | |
475 // Do network I/O between the given buffer and the given socket. | |
476 // Return true if some I/O performed, false otherwise (error or ERR_IO_PENDING) | |
477 bool SSLServerSocketNSS::DoTransportIO() { | |
478 bool network_moved = false; | |
479 if (nss_bufs_ != NULL) { | |
480 int nsent = BufferSend(); | |
481 int nreceived = BufferRecv(); | |
482 network_moved = (nsent > 0 || nreceived >= 0); | |
483 } | |
484 return network_moved; | |
485 } | |
486 | |
487 int SSLServerSocketNSS::DoPayloadRead() { | |
488 DCHECK(user_read_buf_); | |
489 DCHECK_GT(user_read_buf_len_, 0); | |
490 int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_); | |
491 if (rv >= 0) | |
492 return rv; | |
493 PRErrorCode prerr = PR_GetError(); | |
494 if (prerr == PR_WOULD_BLOCK_ERROR) { | |
495 return ERR_IO_PENDING; | |
496 } | |
497 rv = MapNSSError(prerr); | |
498 net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, | |
499 make_scoped_refptr(new SSLErrorParams(rv, prerr))); | |
500 return rv; | |
501 } | |
502 | |
503 int SSLServerSocketNSS::DoPayloadWrite() { | |
504 DCHECK(user_write_buf_); | |
505 int rv = PR_Write(nss_fd_, user_write_buf_->data(), user_write_buf_len_); | |
506 if (rv >= 0) | |
507 return rv; | |
508 PRErrorCode prerr = PR_GetError(); | |
509 if (prerr == PR_WOULD_BLOCK_ERROR) { | |
510 return ERR_IO_PENDING; | |
511 } | |
512 rv = MapNSSError(prerr); | |
513 net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR, | |
514 make_scoped_refptr(new SSLErrorParams(rv, prerr))); | |
515 return rv; | |
516 } | |
517 | |
518 int SSLServerSocketNSS::DoHandshakeLoop(int last_io_result) { | |
519 bool network_moved; | |
520 int rv = last_io_result; | |
521 do { | |
522 // Default to STATE_NONE for next state. | |
523 // (This is a quirk carried over from the windows | |
524 // implementation. It makes reading the logs a bit harder.) | |
525 // State handlers can and often do call GotoState just | |
526 // to stay in the current state. | |
527 State state = next_handshake_state_; | |
528 GotoState(STATE_NONE); | |
529 switch (state) { | |
530 case STATE_NONE: | |
531 // we're just pumping data between the buffer and the network | |
532 break; | |
533 case STATE_HANDSHAKE: | |
534 rv = DoHandshake(); | |
535 break; | |
536 default: | |
537 rv = ERR_UNEXPECTED; | |
538 LOG(DFATAL) << "unexpected state " << state; | |
539 break; | |
540 } | |
541 | |
542 // Do the actual network I/O | |
543 network_moved = DoTransportIO(); | |
544 } while ((rv != ERR_IO_PENDING || network_moved) && | |
545 next_handshake_state_ != STATE_NONE); | |
546 return rv; | |
547 } | |
548 | |
549 int SSLServerSocketNSS::DoReadLoop(int result) { | |
550 DCHECK(completed_handshake_); | |
551 DCHECK(next_handshake_state_ == STATE_NONE); | |
552 | |
553 if (result < 0) | |
554 return result; | |
555 | |
556 if (!nss_bufs_) { | |
557 LOG(DFATAL) << "!nss_bufs_"; | |
558 int rv = ERR_UNEXPECTED; | |
559 net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR, | |
560 make_scoped_refptr(new SSLErrorParams(rv, 0))); | |
561 return rv; | |
562 } | |
563 | |
564 bool network_moved; | |
565 int rv; | |
566 do { | |
567 rv = DoPayloadRead(); | |
568 network_moved = DoTransportIO(); | |
569 } while (rv == ERR_IO_PENDING && network_moved); | |
570 return rv; | |
571 } | |
572 | |
573 int SSLServerSocketNSS::DoWriteLoop(int result) { | |
574 DCHECK(completed_handshake_); | |
575 DCHECK(next_handshake_state_ == STATE_NONE); | |
576 | |
577 if (result < 0) | |
578 return result; | |
579 | |
580 if (!nss_bufs_) { | |
581 LOG(DFATAL) << "!nss_bufs_"; | |
582 int rv = ERR_UNEXPECTED; | |
583 net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR, | |
584 make_scoped_refptr(new SSLErrorParams(rv, 0))); | |
585 return rv; | |
586 } | |
587 | |
588 bool network_moved; | |
589 int rv; | |
590 do { | |
591 rv = DoPayloadWrite(); | |
592 network_moved = DoTransportIO(); | |
593 } while (rv == ERR_IO_PENDING && network_moved); | |
594 return rv; | |
595 } | |
596 | |
597 int SSLServerSocketNSS::DoHandshake() { | |
598 int net_error = net::OK; | |
599 SECStatus rv = SSL_ForceHandshake(nss_fd_); | |
600 | |
601 if (rv == SECSuccess) { | |
602 completed_handshake_ = true; | |
603 } else { | |
604 PRErrorCode prerr = PR_GetError(); | |
605 net_error = MapHandshakeError(prerr); | |
606 | |
607 // If not done, stay in this state | |
608 if (net_error == ERR_IO_PENDING) { | |
609 GotoState(STATE_HANDSHAKE); | |
610 } else { | |
611 LOG(ERROR) << "handshake failed; NSS error code " << prerr | |
612 << ", net_error " << net_error; | |
613 net_log_.AddEvent( | |
614 NetLog::TYPE_SSL_HANDSHAKE_ERROR, | |
615 make_scoped_refptr(new SSLErrorParams(net_error, prerr))); | |
616 } | |
617 } | |
618 return net_error; | |
619 } | |
620 | |
621 } // namespace net | |
OLD | NEW |