Chromium Code Reviews| 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 |