blob: 62e348b4f1ea604c2b12748a7d23680a897a59bb [file] [log] [blame]
[email protected]b43c97c2008-10-22 19:50:581// Copyright (c) 2006-2008 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/base/ssl_client_socket_nss.h"
6
7#include <nspr.h>
8#include <nss.h>
[email protected]ea224582008-12-07 20:25:469#include <secerr.h>
[email protected]b43c97c2008-10-22 19:50:5810// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
11// until NSS 3.12.2 comes out and we update to it.
12#define Lock FOO_NSS_Lock
13#include <ssl.h>
[email protected]ea224582008-12-07 20:25:4614#include <sslerr.h>
[email protected]b43c97c2008-10-22 19:50:5815#include <pk11pub.h>
16#undef Lock
17
18#include "base/logging.h"
19#include "base/nss_init.h"
20#include "base/string_util.h"
21#include "net/base/net_errors.h"
22#include "net/base/ssl_info.h"
23
24static const int kRecvBufferSize = 4096;
25
[email protected]9f8821ed2008-12-09 18:02:3726namespace {
27
28// NSS calls this if an incoming certificate is invalid.
29SECStatus OwnBadCertHandler(void* arg, PRFileDesc* socket) {
[email protected]ea224582008-12-07 20:25:4630 PRErrorCode err = PR_GetError();
31 LOG(INFO) << "server certificate is invalid; NSS error code " << err;
32 // Return SECSuccess to override the problem,
33 // or SECFailure to let the original function fail
34 // Chromium wants it to fail here, and may retry it later.
[email protected]9f8821ed2008-12-09 18:02:3735 LOG(WARNING) << "TODO(dkegel): return SECFailure here";
36 return SECSuccess;
[email protected]b43c97c2008-10-22 19:50:5837}
38
[email protected]9f8821ed2008-12-09 18:02:3739} // anonymous namespace
[email protected]b43c97c2008-10-22 19:50:5840
41namespace net {
42
[email protected]e17b4c12008-11-05 22:04:0843// State machines are easier to debug if you log state transitions.
44// Enable these if you want to see what's going on.
45#if 1
46#define EnterFunction(x)
47#define LeaveFunction(x)
48#define GotoState(s) next_state_ = s
[email protected]ea224582008-12-07 20:25:4649#define LogData(s, len)
[email protected]e17b4c12008-11-05 22:04:0850#else
51#define EnterFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
52 " enter " << x << "; next_state " << next_state_
53#define LeaveFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
54 " leave " << x << "; next_state " << next_state_
55#define GotoState(s) do { LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
56 " jump to state " << s; next_state_ = s; } while (0)
[email protected]ea224582008-12-07 20:25:4657#define LogData(s, len) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
58 " data [" << std::string(s, len) << "]";
59
[email protected]e17b4c12008-11-05 22:04:0860#endif
61
[email protected]ea224582008-12-07 20:25:4662namespace {
63
64int NetErrorFromNSPRError(PRErrorCode err) {
65 // TODO(port): fill this out as we learn what's important
66 switch (err) {
67 case PR_WOULD_BLOCK_ERROR:
68 return ERR_IO_PENDING;
69 case SSL_ERROR_NO_CYPHER_OVERLAP:
70 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
71 case SSL_ERROR_BAD_CERT_DOMAIN:
72 return ERR_CERT_COMMON_NAME_INVALID;
73 case SEC_ERROR_EXPIRED_CERTIFICATE:
74 return ERR_CERT_DATE_INVALID;
75 case SEC_ERROR_BAD_SIGNATURE:
76 return ERR_CERT_INVALID;
77 case SSL_ERROR_REVOKED_CERT_ALERT:
78 case SEC_ERROR_REVOKED_CERTIFICATE:
79 case SEC_ERROR_REVOKED_KEY:
80 return ERR_CERT_REVOKED;
81 case SEC_ERROR_UNKNOWN_ISSUER:
82 return ERR_CERT_AUTHORITY_INVALID;
83
84 default: {
85 if (IS_SSL_ERROR(err)) {
86 LOG(WARNING) << "Unknown SSL error " << err <<
87 " mapped to net::ERR_SSL_PROTOCOL_ERROR";
88 return ERR_SSL_PROTOCOL_ERROR;
89 }
90 if (IS_SEC_ERROR(err)) {
91 // TODO(port): Probably not the best mapping
92 LOG(WARNING) << "Unknown SEC error " << err <<
93 " mapped to net::ERR_CERT_INVALID";
94 return ERR_CERT_INVALID;
95 }
96 LOG(WARNING) << "Unknown error " << err <<
97 " mapped to net::ERR_FAILED";
98 return ERR_FAILED;
99 }
100 }
101}
102
103// Shared with the Windows code. TODO(avi): merge to a common place
104int CertStatusFromNetError(int error) {
105 switch (error) {
106 case ERR_CERT_COMMON_NAME_INVALID:
107 return CERT_STATUS_COMMON_NAME_INVALID;
108 case ERR_CERT_DATE_INVALID:
109 return CERT_STATUS_DATE_INVALID;
110 case ERR_CERT_AUTHORITY_INVALID:
111 return CERT_STATUS_AUTHORITY_INVALID;
112 case ERR_CERT_NO_REVOCATION_MECHANISM:
113 return CERT_STATUS_NO_REVOCATION_MECHANISM;
114 case ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
115 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
116 case ERR_CERT_REVOKED:
117 return CERT_STATUS_REVOKED;
118 case ERR_CERT_CONTAINS_ERRORS:
119 NOTREACHED();
120 // Falls through.
121 case ERR_CERT_INVALID:
122 return CERT_STATUS_INVALID;
123 default:
124 return 0;
125 }
126}
127
128} // namespace
129
[email protected]b43c97c2008-10-22 19:50:58130bool SSLClientSocketNSS::nss_options_initialized_ = false;
131
132SSLClientSocketNSS::SSLClientSocketNSS(ClientSocket* transport_socket,
133 const std::string& hostname,
134 const SSLConfig& ssl_config)
[email protected]ea224582008-12-07 20:25:46135 :
[email protected]b43c97c2008-10-22 19:50:58136 buffer_send_callback_(this, &SSLClientSocketNSS::BufferSendComplete),
137 buffer_recv_callback_(this, &SSLClientSocketNSS::BufferRecvComplete),
138 transport_send_busy_(false),
139 transport_recv_busy_(false),
140 io_callback_(this, &SSLClientSocketNSS::OnIOComplete),
141 transport_(transport_socket),
142 hostname_(hostname),
143 ssl_config_(ssl_config),
144 user_callback_(NULL),
145 user_buf_(NULL),
146 user_buf_len_(0),
[email protected]ea224582008-12-07 20:25:46147 server_cert_status_(0),
[email protected]b43c97c2008-10-22 19:50:58148 completed_handshake_(false),
149 next_state_(STATE_NONE),
150 nss_fd_(NULL),
151 nss_bufs_(NULL) {
[email protected]e17b4c12008-11-05 22:04:08152 EnterFunction("");
[email protected]b43c97c2008-10-22 19:50:58153}
154
155SSLClientSocketNSS::~SSLClientSocketNSS() {
[email protected]e17b4c12008-11-05 22:04:08156 EnterFunction("");
[email protected]b43c97c2008-10-22 19:50:58157 Disconnect();
[email protected]e17b4c12008-11-05 22:04:08158 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58159}
160
161int SSLClientSocketNSS::Init() {
[email protected]e17b4c12008-11-05 22:04:08162 EnterFunction("");
163 // Call NSS_NoDB_Init() in a threadsafe way.
164 base::EnsureNSSInit();
[email protected]b43c97c2008-10-22 19:50:58165
[email protected]e17b4c12008-11-05 22:04:08166 LeaveFunction("");
167 return OK;
[email protected]b43c97c2008-10-22 19:50:58168}
169
170int SSLClientSocketNSS::Connect(CompletionCallback* callback) {
[email protected]e17b4c12008-11-05 22:04:08171 EnterFunction("");
[email protected]b43c97c2008-10-22 19:50:58172 DCHECK(transport_.get());
173 DCHECK(next_state_ == STATE_NONE);
174 DCHECK(!user_callback_);
175
[email protected]e17b4c12008-11-05 22:04:08176 GotoState(STATE_CONNECT);
[email protected]b43c97c2008-10-22 19:50:58177 int rv = DoLoop(OK);
178 if (rv == ERR_IO_PENDING)
179 user_callback_ = callback;
[email protected]e17b4c12008-11-05 22:04:08180
181 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58182 return rv;
183}
184
[email protected]ea224582008-12-07 20:25:46185int SSLClientSocketNSS::ReconnectIgnoringLastError(
186 CompletionCallback* callback) {
[email protected]e17b4c12008-11-05 22:04:08187 EnterFunction("");
[email protected]b43c97c2008-10-22 19:50:58188 // TODO(darin): implement me!
[email protected]e17b4c12008-11-05 22:04:08189 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58190 return ERR_FAILED;
191}
192
193void SSLClientSocketNSS::Disconnect() {
[email protected]e17b4c12008-11-05 22:04:08194 EnterFunction("");
[email protected]b43c97c2008-10-22 19:50:58195 // TODO(wtc): Send SSL close_notify alert.
196 if (nss_fd_ != NULL) {
197 PR_Close(nss_fd_);
198 nss_fd_ = NULL;
199 }
200 completed_handshake_ = false;
201 transport_->Disconnect();
[email protected]e17b4c12008-11-05 22:04:08202 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58203}
204
205bool SSLClientSocketNSS::IsConnected() const {
[email protected]e17b4c12008-11-05 22:04:08206 EnterFunction("");
207 bool ret = completed_handshake_ && transport_->IsConnected();
208 LeaveFunction("");
209 return ret;
[email protected]b43c97c2008-10-22 19:50:58210}
211
212int SSLClientSocketNSS::Read(char* buf, int buf_len,
[email protected]ea224582008-12-07 20:25:46213 CompletionCallback* callback) {
[email protected]e17b4c12008-11-05 22:04:08214 EnterFunction(buf_len);
[email protected]b43c97c2008-10-22 19:50:58215 DCHECK(completed_handshake_);
216 DCHECK(next_state_ == STATE_NONE);
217 DCHECK(!user_callback_);
[email protected]e17b4c12008-11-05 22:04:08218 DCHECK(!user_buf_);
[email protected]b43c97c2008-10-22 19:50:58219
220 user_buf_ = buf;
221 user_buf_len_ = buf_len;
222
[email protected]e17b4c12008-11-05 22:04:08223 GotoState(STATE_PAYLOAD_READ);
[email protected]b43c97c2008-10-22 19:50:58224 int rv = DoLoop(OK);
225 if (rv == ERR_IO_PENDING)
226 user_callback_ = callback;
[email protected]ea224582008-12-07 20:25:46227 LeaveFunction(rv);
[email protected]b43c97c2008-10-22 19:50:58228 return rv;
229}
230
231int SSLClientSocketNSS::Write(const char* buf, int buf_len,
232 CompletionCallback* callback) {
[email protected]e17b4c12008-11-05 22:04:08233 EnterFunction(buf_len);
[email protected]b43c97c2008-10-22 19:50:58234 DCHECK(completed_handshake_);
235 DCHECK(next_state_ == STATE_NONE);
236 DCHECK(!user_callback_);
[email protected]e17b4c12008-11-05 22:04:08237 DCHECK(!user_buf_);
[email protected]b43c97c2008-10-22 19:50:58238
239 user_buf_ = const_cast<char*>(buf);
240 user_buf_len_ = buf_len;
241
[email protected]e17b4c12008-11-05 22:04:08242 GotoState(STATE_PAYLOAD_WRITE);
[email protected]b43c97c2008-10-22 19:50:58243 int rv = DoLoop(OK);
244 if (rv == ERR_IO_PENDING)
245 user_callback_ = callback;
[email protected]ea224582008-12-07 20:25:46246 LeaveFunction(rv);
[email protected]b43c97c2008-10-22 19:50:58247 return rv;
248}
249
250void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
[email protected]e17b4c12008-11-05 22:04:08251 EnterFunction("");
[email protected]b43c97c2008-10-22 19:50:58252 ssl_info->Reset();
[email protected]ea224582008-12-07 20:25:46253 SSLChannelInfo channel_info;
254 SECStatus ok = SSL_GetChannelInfo(nss_fd_,
255 &channel_info, sizeof(channel_info));
[email protected]9f8821ed2008-12-09 18:02:37256 if (ok == SECSuccess &&
257 channel_info.length == sizeof(channel_info) &&
258 channel_info.cipherSuite) {
[email protected]ea224582008-12-07 20:25:46259 SSLCipherSuiteInfo cipher_info;
260 ok = SSL_GetCipherSuiteInfo(channel_info.cipherSuite,
261 &cipher_info, sizeof(cipher_info));
262 if (ok == SECSuccess) {
263 ssl_info->security_bits = cipher_info.effectiveKeyBits;
264 } else {
265 ssl_info->security_bits = -1;
[email protected]9f8821ed2008-12-09 18:02:37266 LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError()
267 << " for cipherSuite " << channel_info.cipherSuite;
[email protected]ea224582008-12-07 20:25:46268 }
269 }
270 ssl_info->cert_status = server_cert_status_;
271 // TODO(port): implement X509Certificate so we can set the cert field!
272 // CERTCertificate *nssCert = SSL_PeerCertificate(nss_fd_);
[email protected]e17b4c12008-11-05 22:04:08273 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58274}
275
276void SSLClientSocketNSS::DoCallback(int rv) {
[email protected]e17b4c12008-11-05 22:04:08277 EnterFunction(rv);
[email protected]b43c97c2008-10-22 19:50:58278 DCHECK(rv != ERR_IO_PENDING);
279 DCHECK(user_callback_);
280
281 // since Run may result in Read being called, clear user_callback_ up front.
282 CompletionCallback* c = user_callback_;
283 user_callback_ = NULL;
284 c->Run(rv);
[email protected]e17b4c12008-11-05 22:04:08285 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58286}
287
288void SSLClientSocketNSS::OnIOComplete(int result) {
[email protected]e17b4c12008-11-05 22:04:08289 EnterFunction(result);
[email protected]b43c97c2008-10-22 19:50:58290 int rv = DoLoop(result);
[email protected]e17b4c12008-11-05 22:04:08291 if (rv != ERR_IO_PENDING && user_callback_ != NULL)
[email protected]b43c97c2008-10-22 19:50:58292 DoCallback(rv);
[email protected]e17b4c12008-11-05 22:04:08293 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58294}
295
296// Map a Chromium net error code to an NSS error code
297// See _MD_unix_map_default_error in the NSS source
298// tree for inspiration.
299static PRErrorCode MapErrorToNSS(int result) {
300 if (result >=0)
301 return result;
302 // TODO(port): add real table
303 LOG(ERROR) << "MapErrorToNSS " << result;
304 return PR_UNKNOWN_ERROR;
305}
306
[email protected]ea224582008-12-07 20:25:46307/*
[email protected]b43c97c2008-10-22 19:50:58308 * Do network I/O between the given buffer and the given socket.
[email protected]ea224582008-12-07 20:25:46309 * Return 0 for EOF,
[email protected]b43c97c2008-10-22 19:50:58310 * > 0 for bytes transferred immediately,
311 * < 0 for error (or the non-error ERR_IO_PENDING).
312 */
313int SSLClientSocketNSS::BufferSend(void) {
314 if (transport_send_busy_) return ERR_IO_PENDING;
315
316 const char *buf;
317 int nb = memio_GetWriteParams(nss_bufs_, &buf);
[email protected]e17b4c12008-11-05 22:04:08318 EnterFunction(nb);
[email protected]b43c97c2008-10-22 19:50:58319
320 int rv;
321 if (!nb) {
322 rv = OK;
323 } else {
324 rv = transport_->Write(buf, nb, &buffer_send_callback_);
325 if (rv == ERR_IO_PENDING)
326 transport_send_busy_ = true;
327 else
328 memio_PutWriteResult(nss_bufs_, MapErrorToNSS(rv));
329 }
330
[email protected]e17b4c12008-11-05 22:04:08331 LeaveFunction(rv);
[email protected]b43c97c2008-10-22 19:50:58332 return rv;
333}
334
335void SSLClientSocketNSS::BufferSendComplete(int result) {
[email protected]e17b4c12008-11-05 22:04:08336 EnterFunction(result);
[email protected]b43c97c2008-10-22 19:50:58337 memio_PutWriteResult(nss_bufs_, result);
338 transport_send_busy_ = false;
339 OnIOComplete(result);
[email protected]e17b4c12008-11-05 22:04:08340 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58341}
342
343
344int SSLClientSocketNSS::BufferRecv(void) {
[email protected]b43c97c2008-10-22 19:50:58345 if (transport_recv_busy_) return ERR_IO_PENDING;
346
347 char *buf;
348 int nb = memio_GetReadParams(nss_bufs_, &buf);
[email protected]e17b4c12008-11-05 22:04:08349 EnterFunction(nb);
[email protected]b43c97c2008-10-22 19:50:58350 int rv;
351 if (!nb) {
352 // buffer too full to read into, so no I/O possible at moment
353 rv = ERR_IO_PENDING;
354 } else {
355 rv = transport_->Read(buf, nb, &buffer_recv_callback_);
356 if (rv == ERR_IO_PENDING)
357 transport_recv_busy_ = true;
358 else
359 memio_PutReadResult(nss_bufs_, MapErrorToNSS(rv));
360 }
[email protected]e17b4c12008-11-05 22:04:08361 LeaveFunction(rv);
[email protected]b43c97c2008-10-22 19:50:58362 return rv;
363}
364
365void SSLClientSocketNSS::BufferRecvComplete(int result) {
[email protected]e17b4c12008-11-05 22:04:08366 EnterFunction(result);
[email protected]b43c97c2008-10-22 19:50:58367 memio_PutReadResult(nss_bufs_, result);
368 transport_recv_busy_ = false;
369 OnIOComplete(result);
[email protected]e17b4c12008-11-05 22:04:08370 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58371}
372
373
374int SSLClientSocketNSS::DoLoop(int last_io_result) {
[email protected]e17b4c12008-11-05 22:04:08375 EnterFunction(last_io_result);
[email protected]b43c97c2008-10-22 19:50:58376 bool network_moved;
377 int rv = last_io_result;
378 do {
379 network_moved = false;
[email protected]e17b4c12008-11-05 22:04:08380 // Default to STATE_NONE for next state.
[email protected]ea224582008-12-07 20:25:46381 // (This is a quirk carried over from the windows
[email protected]e17b4c12008-11-05 22:04:08382 // implementation. It makes reading the logs a bit harder.)
[email protected]ea224582008-12-07 20:25:46383 // State handlers can and often do call GotoState just
[email protected]e17b4c12008-11-05 22:04:08384 // to stay in the current state.
[email protected]b43c97c2008-10-22 19:50:58385 State state = next_state_;
[email protected]e17b4c12008-11-05 22:04:08386 GotoState(STATE_NONE);
[email protected]b43c97c2008-10-22 19:50:58387 switch (state) {
[email protected]e17b4c12008-11-05 22:04:08388 case STATE_NONE:
389 // we're just pumping data between the buffer and the network
390 break;
[email protected]b43c97c2008-10-22 19:50:58391 case STATE_CONNECT:
392 rv = DoConnect();
393 break;
394 case STATE_CONNECT_COMPLETE:
395 rv = DoConnectComplete(rv);
396 break;
397 case STATE_HANDSHAKE_READ:
398 rv = DoHandshakeRead();
399 break;
400 case STATE_PAYLOAD_READ:
401 rv = DoPayloadRead();
402 break;
403 case STATE_PAYLOAD_WRITE:
404 rv = DoPayloadWrite();
405 break;
406 default:
407 rv = ERR_UNEXPECTED;
408 NOTREACHED() << "unexpected state";
409 break;
410 }
411
412 // Do the actual network I/O
413 if (nss_bufs_ != NULL) {
414 int nsent = BufferSend();
415 int nreceived = BufferRecv();
416 network_moved = (nsent > 0 || nreceived >= 0);
417 }
418 } while ((rv != ERR_IO_PENDING || network_moved) && next_state_ != STATE_NONE);
[email protected]e17b4c12008-11-05 22:04:08419 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58420 return rv;
421}
422
423int SSLClientSocketNSS::DoConnect() {
[email protected]e17b4c12008-11-05 22:04:08424 EnterFunction("");
425 GotoState(STATE_CONNECT_COMPLETE);
[email protected]b43c97c2008-10-22 19:50:58426 return transport_->Connect(&io_callback_);
427}
428
429int SSLClientSocketNSS::DoConnectComplete(int result) {
[email protected]e17b4c12008-11-05 22:04:08430 EnterFunction(result);
[email protected]b43c97c2008-10-22 19:50:58431 if (result < 0)
432 return result;
433
434 if (Init() != OK) {
435 NOTREACHED() << "Couldn't initialize nss";
436 }
437
438 // Transport connected, now hook it up to nss
439 // TODO(port): specify rx and tx buffer sizes separately
440 nss_fd_ = memio_CreateIOLayer(kRecvBufferSize);
441 if (nss_fd_ == NULL) {
442 return 9999; // TODO(port): real error
443 }
444
445 // Tell NSS who we're connected to
446 PRNetAddr peername;
447 socklen_t len = sizeof(PRNetAddr);
448 int err = transport_->GetPeerName((struct sockaddr *)&peername, &len);
449 if (err) {
450 DLOG(ERROR) << "GetPeerName failed";
451 return 9999; // TODO(port): real error
452 }
453 memio_SetPeerName(nss_fd_, &peername);
454
[email protected]ea224582008-12-07 20:25:46455 // Grab pointer to buffers
[email protected]b43c97c2008-10-22 19:50:58456 nss_bufs_ = memio_GetSecret(nss_fd_);
457
458 /* Create SSL state machine */
459 /* Push SSL onto our fake I/O socket */
460 nss_fd_ = SSL_ImportFD(NULL, nss_fd_);
461 if (nss_fd_ == NULL) {
462 return ERR_SSL_PROTOCOL_ERROR; // TODO(port): real error
463 }
464 // TODO(port): set more ssl options! Check errors!
465
466 int rv;
467
468 rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE);
469 if (rv != SECSuccess)
470 return ERR_UNEXPECTED;
471
472 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, ssl_config_.ssl2_enabled);
473 if (rv != SECSuccess)
474 return ERR_UNEXPECTED;
475
[email protected]ea224582008-12-07 20:25:46476 // SNI is enabled automatically if TLS is enabled -- as long as
477 // SSL_V2_COMPATIBLE_HELLO isn't.
478 // So don't do V2 compatible hellos unless we're really using SSL2,
479 // to avoid errors like
480 // "common name `mail.google.com' != requested host name `gmail.com'"
481 rv = SSL_OptionSet(nss_fd_, SSL_V2_COMPATIBLE_HELLO,
482 ssl_config_.ssl2_enabled);
483 if (rv != SECSuccess)
484 return ERR_UNEXPECTED;
485
[email protected]b43c97c2008-10-22 19:50:58486 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, ssl_config_.ssl3_enabled);
487 if (rv != SECSuccess)
488 return ERR_UNEXPECTED;
489
[email protected]ea224582008-12-07 20:25:46490 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_TLS, ssl_config_.tls1_enabled);
[email protected]b43c97c2008-10-22 19:50:58491 if (rv != SECSuccess)
492 return ERR_UNEXPECTED;
493
[email protected]ea224582008-12-07 20:25:46494#ifdef SSL_ENABLE_SESSION_TICKETS
495 // Support RFC 5077
496 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
497 if (rv != SECSuccess)
498 LOG(INFO) << "SSL_ENABLE_SESSION_TICKETS failed. Old system nss?";
499#else
500 #error "You need to install NSS-3.12 or later to build chromium"
501#endif
502
[email protected]b43c97c2008-10-22 19:50:58503 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
504 if (rv != SECSuccess)
505 return ERR_UNEXPECTED;
[email protected]ea224582008-12-07 20:25:46506
[email protected]9f8821ed2008-12-09 18:02:37507 rv = SSL_BadCertHook(nss_fd_, OwnBadCertHandler, NULL);
[email protected]b43c97c2008-10-22 19:50:58508 if (rv != SECSuccess)
509 return ERR_UNEXPECTED;
510
511 // Tell SSL the hostname we're trying to connect to.
512 SSL_SetURL(nss_fd_, hostname_.c_str());
513
514 // Tell SSL we're a client; needed if not letting NSPR do socket I/O
515 SSL_ResetHandshake(nss_fd_, 0);
[email protected]e17b4c12008-11-05 22:04:08516 GotoState(STATE_HANDSHAKE_READ);
[email protected]b43c97c2008-10-22 19:50:58517 // Return OK so DoLoop tries handshaking
[email protected]e17b4c12008-11-05 22:04:08518 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58519 return OK;
520}
521
522int SSLClientSocketNSS::DoHandshakeRead() {
[email protected]e17b4c12008-11-05 22:04:08523 EnterFunction("");
[email protected]ea224582008-12-07 20:25:46524 int net_error;
[email protected]b43c97c2008-10-22 19:50:58525 int rv = SSL_ForceHandshake(nss_fd_);
[email protected]ea224582008-12-07 20:25:46526
[email protected]b43c97c2008-10-22 19:50:58527 if (rv == SECSuccess) {
[email protected]ea224582008-12-07 20:25:46528 net_error = OK;
[email protected]b43c97c2008-10-22 19:50:58529 // there's a callback for this, too
530 completed_handshake_ = true;
531 // Indicate we're ready to handle I/O. Badly named?
[email protected]e17b4c12008-11-05 22:04:08532 GotoState(STATE_NONE);
[email protected]ea224582008-12-07 20:25:46533 } else {
534 PRErrorCode prerr = PR_GetError();
535 net_error = NetErrorFromNSPRError(prerr);
536
537 // If not done, stay in this state
538 if (net_error == ERR_IO_PENDING) {
539 GotoState(STATE_HANDSHAKE_READ);
540 } else {
541 server_cert_status_ = CertStatusFromNetError(net_error);
542 LOG(ERROR) << "handshake failed; NSS error code " << prerr
543 << ", net_error " << net_error << ", server_cert_status "
544 << server_cert_status_;
545 }
[email protected]b43c97c2008-10-22 19:50:58546 }
[email protected]ea224582008-12-07 20:25:46547
[email protected]e17b4c12008-11-05 22:04:08548 LeaveFunction("");
[email protected]ea224582008-12-07 20:25:46549 return net_error;
[email protected]b43c97c2008-10-22 19:50:58550}
[email protected]ea224582008-12-07 20:25:46551
[email protected]b43c97c2008-10-22 19:50:58552int SSLClientSocketNSS::DoPayloadRead() {
[email protected]e17b4c12008-11-05 22:04:08553 EnterFunction(user_buf_len_);
[email protected]b43c97c2008-10-22 19:50:58554 int rv = PR_Read(nss_fd_, user_buf_, user_buf_len_);
[email protected]e17b4c12008-11-05 22:04:08555 if (rv >= 0) {
[email protected]ea224582008-12-07 20:25:46556 LogData(user_buf_, rv);
[email protected]e17b4c12008-11-05 22:04:08557 user_buf_ = NULL;
558 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58559 return rv;
[email protected]e17b4c12008-11-05 22:04:08560 }
[email protected]b43c97c2008-10-22 19:50:58561 PRErrorCode prerr = PR_GetError();
562 if (prerr == PR_WOULD_BLOCK_ERROR) {
[email protected]e17b4c12008-11-05 22:04:08563 GotoState(STATE_PAYLOAD_READ);
564 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58565 return ERR_IO_PENDING;
566 }
[email protected]e17b4c12008-11-05 22:04:08567 user_buf_ = NULL;
568 LeaveFunction("");
[email protected]ea224582008-12-07 20:25:46569 return NetErrorFromNSPRError(prerr);
[email protected]b43c97c2008-10-22 19:50:58570}
571
572int SSLClientSocketNSS::DoPayloadWrite() {
[email protected]e17b4c12008-11-05 22:04:08573 EnterFunction(user_buf_len_);
[email protected]b43c97c2008-10-22 19:50:58574 int rv = PR_Write(nss_fd_, user_buf_, user_buf_len_);
[email protected]e17b4c12008-11-05 22:04:08575 if (rv >= 0) {
[email protected]ea224582008-12-07 20:25:46576 LogData(user_buf_, rv);
[email protected]e17b4c12008-11-05 22:04:08577 user_buf_ = NULL;
578 LeaveFunction("");
[email protected]b43c97c2008-10-22 19:50:58579 return rv;
[email protected]e17b4c12008-11-05 22:04:08580 }
[email protected]b43c97c2008-10-22 19:50:58581 PRErrorCode prerr = PR_GetError();
582 if (prerr == PR_WOULD_BLOCK_ERROR) {
[email protected]e17b4c12008-11-05 22:04:08583 GotoState(STATE_PAYLOAD_WRITE);
[email protected]b43c97c2008-10-22 19:50:58584 return ERR_IO_PENDING;
585 }
[email protected]e17b4c12008-11-05 22:04:08586 user_buf_ = NULL;
587 LeaveFunction("");
[email protected]ea224582008-12-07 20:25:46588 return NetErrorFromNSPRError(prerr);
[email protected]b43c97c2008-10-22 19:50:58589}
590
591} // namespace net
592