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