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

Side by Side Diff: net/base/ssl_client_socket_nss.cc

Issue 115700: Remember the intermediate CA certs if the server sends them to us.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/ssl_client_socket_nss.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // This file includes code GetDefaultCertNickname(), derived from
6 // nsNSSCertificate::defaultServerNickName()
7 // in mozilla/security/manager/ssl/src/nsNSSCertificate.cpp
8 // and SSLClientSocketNSS::OwnAuthCertHandler() derived from
9 // AuthCertificateCallback() in
10 // mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp.
11
12 /* ***** BEGIN LICENSE BLOCK *****
13 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
14 *
15 * The contents of this file are subject to the Mozilla Public License Version
16 * 1.1 (the "License"); you may not use this file except in compliance with
17 * the License. You may obtain a copy of the License at
18 * http://www.mozilla.org/MPL/
19 *
20 * Software distributed under the License is distributed on an "AS IS" basis,
21 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
22 * for the specific language governing rights and limitations under the
23 * License.
24 *
25 * The Original Code is the Netscape security libraries.
26 *
27 * The Initial Developer of the Original Code is
28 * Netscape Communications Corporation.
29 * Portions created by the Initial Developer are Copyright (C) 2000
30 * the Initial Developer. All Rights Reserved.
31 *
32 * Contributor(s):
33 * Ian McGreer <mcgreer@netscape.com>
34 * Javier Delgadillo <javi@netscape.com>
35 * Kai Engert <kengert@redhat.com>
36 *
37 * Alternatively, the contents of this file may be used under the terms of
38 * either the GNU General Public License Version 2 or later (the "GPL"), or
39 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
40 * in which case the provisions of the GPL or the LGPL are applicable instead
41 * of those above. If you wish to allow use of your version of this file only
42 * under the terms of either the GPL or the LGPL, and not to allow others to
43 * use your version of this file under the terms of the MPL, indicate your
44 * decision by deleting the provisions above and replace them with the notice
45 * and other provisions required by the GPL or the LGPL. If you do not delete
46 * the provisions above, a recipient may use your version of this file under
47 * the terms of any one of the MPL, the GPL or the LGPL.
48 *
49 * ***** END LICENSE BLOCK ***** */
50
5 #include "net/base/ssl_client_socket_nss.h" 51 #include "net/base/ssl_client_socket_nss.h"
6 52
53 #include <certdb.h>
7 #include <nspr.h> 54 #include <nspr.h>
8 #include <nss.h> 55 #include <nss.h>
9 #include <secerr.h> 56 #include <secerr.h>
10 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424 57 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
11 // until NSS 3.12.2 comes out and we update to it. 58 // until NSS 3.12.2 comes out and we update to it.
12 #define Lock FOO_NSS_Lock 59 #define Lock FOO_NSS_Lock
13 #include <ssl.h> 60 #include <ssl.h>
14 #include <sslerr.h> 61 #include <sslerr.h>
15 #include <pk11pub.h> 62 #include <pk11pub.h>
16 #undef Lock 63 #undef Lock
(...skipping 23 matching lines...) Expand all
40 " leave " << x << "; next_state " << next_state_ 87 " leave " << x << "; next_state " << next_state_
41 #define GotoState(s) do { LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ 88 #define GotoState(s) do { LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
42 " jump to state " << s; next_state_ = s; } while (0) 89 " jump to state " << s; next_state_ = s; } while (0)
43 #define LogData(s, len) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ 90 #define LogData(s, len) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
44 " data [" << std::string(s, len) << "]"; 91 " data [" << std::string(s, len) << "]";
45 92
46 #endif 93 #endif
47 94
48 namespace { 95 namespace {
49 96
97 // Gets default certificate nickname from cert.
98 // Derived from nsNSSCertificate::defaultServerNickname
99 // in mozilla/security/manager/ssl/src/nsNSSCertificate.cpp.
100 std::string GetDefaultCertNickname(
101 net::X509Certificate::OSCertHandle cert) {
102 if (cert == NULL)
103 return "";
104
105 char* name = CERT_GetCommonName(&cert->subject);
106 if (!name) {
107 // Certs without common names are strange, but they do exist...
108 // Let's try to use another string for the nickname
109 name = CERT_GetOrgUnitName(&cert->subject);
110 if (!name)
111 name = CERT_GetOrgName(&cert->subject);
112 if (!name)
113 name = CERT_GetLocalityName(&cert->subject);
114 if (!name)
115 name = CERT_GetStateName(&cert->subject);
116 if (!name)
117 name = CERT_GetCountryName(&cert->subject);
118 if (!name)
119 return "";
120 }
121 int count = 1;
122 std::string nickname;
123 while (1) {
124 if (count == 1) {
125 nickname = name;
126 } else {
127 nickname = StringPrintf("%s #%d", name, count);
128 }
129 PRBool conflict = SEC_CertNicknameConflict(
130 const_cast<char*>(nickname.c_str()), &cert->derSubject, cert->dbhandle);
131 if (!conflict)
132 break;
133 count++;
134 }
135 PR_FREEIF(name);
136 return nickname;
137 }
138
50 int NetErrorFromNSPRError(PRErrorCode err) { 139 int NetErrorFromNSPRError(PRErrorCode err) {
51 // TODO(port): fill this out as we learn what's important 140 // TODO(port): fill this out as we learn what's important
52 switch (err) { 141 switch (err) {
53 case PR_WOULD_BLOCK_ERROR: 142 case PR_WOULD_BLOCK_ERROR:
54 return ERR_IO_PENDING; 143 return ERR_IO_PENDING;
55 case SSL_ERROR_NO_CYPHER_OVERLAP: 144 case SSL_ERROR_NO_CYPHER_OVERLAP:
56 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; 145 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
57 case SSL_ERROR_BAD_CERT_DOMAIN: 146 case SSL_ERROR_BAD_CERT_DOMAIN:
58 return ERR_CERT_COMMON_NAME_INVALID; 147 return ERR_CERT_COMMON_NAME_INVALID;
59 case SEC_ERROR_EXPIRED_CERTIFICATE: 148 case SEC_ERROR_EXPIRED_CERTIFICATE:
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 buffer_recv_callback_(this, &SSLClientSocketNSS::BufferRecvComplete), 190 buffer_recv_callback_(this, &SSLClientSocketNSS::BufferRecvComplete),
102 transport_send_busy_(false), 191 transport_send_busy_(false),
103 transport_recv_busy_(false), 192 transport_recv_busy_(false),
104 io_callback_(this, &SSLClientSocketNSS::OnIOComplete), 193 io_callback_(this, &SSLClientSocketNSS::OnIOComplete),
105 transport_(transport_socket), 194 transport_(transport_socket),
106 hostname_(hostname), 195 hostname_(hostname),
107 ssl_config_(ssl_config), 196 ssl_config_(ssl_config),
108 user_callback_(NULL), 197 user_callback_(NULL),
109 user_buf_len_(0), 198 user_buf_len_(0),
110 server_cert_error_(0), 199 server_cert_error_(0),
200 cert_list_(NULL),
111 completed_handshake_(false), 201 completed_handshake_(false),
112 next_state_(STATE_NONE), 202 next_state_(STATE_NONE),
113 nss_fd_(NULL), 203 nss_fd_(NULL),
114 nss_bufs_(NULL) { 204 nss_bufs_(NULL) {
115 EnterFunction(""); 205 EnterFunction("");
116 } 206 }
117 207
118 SSLClientSocketNSS::~SSLClientSocketNSS() { 208 SSLClientSocketNSS::~SSLClientSocketNSS() {
119 EnterFunction(""); 209 EnterFunction("");
120 Disconnect(); 210 Disconnect();
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 void SSLClientSocketNSS::InvalidateSessionIfBadCertificate() { 353 void SSLClientSocketNSS::InvalidateSessionIfBadCertificate() {
264 if (UpdateServerCert() != NULL && 354 if (UpdateServerCert() != NULL &&
265 ssl_config_.allowed_bad_certs_.count(server_cert_)) { 355 ssl_config_.allowed_bad_certs_.count(server_cert_)) {
266 SSL_InvalidateSession(nss_fd_); 356 SSL_InvalidateSession(nss_fd_);
267 } 357 }
268 } 358 }
269 359
270 void SSLClientSocketNSS::Disconnect() { 360 void SSLClientSocketNSS::Disconnect() {
271 EnterFunction(""); 361 EnterFunction("");
272 362
273 // Reset object state
274 transport_send_busy_ = false;
275 transport_recv_busy_ = false;
276 user_buf_ = NULL;
277 user_buf_len_ = 0;
278 server_cert_error_ = OK;
279 completed_handshake_ = false;
280 nss_bufs_ = NULL;
281
282 // TODO(wtc): Send SSL close_notify alert. 363 // TODO(wtc): Send SSL close_notify alert.
283 if (nss_fd_ != NULL) { 364 if (nss_fd_ != NULL) {
284 InvalidateSessionIfBadCertificate(); 365 InvalidateSessionIfBadCertificate();
285 PR_Close(nss_fd_); 366 PR_Close(nss_fd_);
286 nss_fd_ = NULL; 367 nss_fd_ = NULL;
287 } 368 }
288 369
289 transport_->Disconnect(); 370 transport_->Disconnect();
371
372 // Reset object state
373 transport_send_busy_ = false;
374 transport_recv_busy_ = false;
375 user_buf_ = NULL;
376 user_buf_len_ = 0;
377 server_cert_ = NULL;
378 server_cert_error_ = OK;
379 if (cert_list_) {
380 CERT_DestroyCertList(cert_list_);
381 cert_list_ = NULL;
382 }
383 completed_handshake_ = false;
384 nss_bufs_ = NULL;
385
290 LeaveFunction(""); 386 LeaveFunction("");
291 } 387 }
292 388
293 bool SSLClientSocketNSS::IsConnected() const { 389 bool SSLClientSocketNSS::IsConnected() const {
294 // Ideally, we should also check if we have received the close_notify alert 390 // Ideally, we should also check if we have received the close_notify alert
295 // message from the server, and return false in that case. We're not doing 391 // message from the server, and return false in that case. We're not doing
296 // that, so this function may return a false positive. Since the upper 392 // that, so this function may return a false positive. Since the upper
297 // layer (HttpNetworkTransaction) needs to handle a persistent connection 393 // layer (HttpNetworkTransaction) needs to handle a persistent connection
298 // closed by the server when we send a request anyway, a false positive in 394 // closed by the server when we send a request anyway, a false positive in
299 // exchange for simpler code is a good trade-off. 395 // exchange for simpler code is a good trade-off.
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 453
358 X509Certificate *SSLClientSocketNSS::UpdateServerCert() { 454 X509Certificate *SSLClientSocketNSS::UpdateServerCert() {
359 // We set the server_cert_ from OwnAuthCertHandler(), but this handler 455 // We set the server_cert_ from OwnAuthCertHandler(), but this handler
360 // does not necessarily get called if we are continuing a cached SSL 456 // does not necessarily get called if we are continuing a cached SSL
361 // session. 457 // session.
362 if (server_cert_ == NULL) { 458 if (server_cert_ == NULL) {
363 X509Certificate::OSCertHandle nss_cert = SSL_PeerCertificate(nss_fd_); 459 X509Certificate::OSCertHandle nss_cert = SSL_PeerCertificate(nss_fd_);
364 if (nss_cert) { 460 if (nss_cert) {
365 server_cert_ = X509Certificate::CreateFromHandle( 461 server_cert_ = X509Certificate::CreateFromHandle(
366 nss_cert, X509Certificate::SOURCE_FROM_NETWORK); 462 nss_cert, X509Certificate::SOURCE_FROM_NETWORK);
463 DCHECK(!cert_list_);
464 cert_list_ = CERT_GetCertChainFromCert(
465 nss_cert, PR_Now(), certUsageSSLCA);
367 } 466 }
368 } 467 }
369 return server_cert_; 468 return server_cert_;
370 } 469 }
371 470
372 void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { 471 void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
373 EnterFunction(""); 472 EnterFunction("");
374 ssl_info->Reset(); 473 ssl_info->Reset();
375 SSLChannelInfo channel_info; 474 SSLChannelInfo channel_info;
376 SECStatus ok = SSL_GetChannelInfo(nss_fd_, 475 SECStatus ok = SSL_GetChannelInfo(nss_fd_,
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 network_moved = (nsent > 0 || nreceived >= 0); 644 network_moved = (nsent > 0 || nreceived >= 0);
546 } 645 }
547 } while ((rv != ERR_IO_PENDING || network_moved) && 646 } while ((rv != ERR_IO_PENDING || network_moved) &&
548 next_state_ != STATE_NONE); 647 next_state_ != STATE_NONE);
549 LeaveFunction(""); 648 LeaveFunction("");
550 return rv; 649 return rv;
551 } 650 }
552 651
553 // static 652 // static
554 // NSS calls this if an incoming certificate needs to be verified. 653 // NSS calls this if an incoming certificate needs to be verified.
654 // Derived from AuthCertificateCallback() in
655 // mozilla/source/security/manager/ssl/src/nsNSSCallbacks.cpp.
555 SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg, 656 SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg,
556 PRFileDesc* socket, 657 PRFileDesc* socket,
557 PRBool checksig, 658 PRBool checksig,
558 PRBool is_server) { 659 PRBool is_server) {
559 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); 660 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg);
560 661
561 // Remember the certificate as it will no longer be accessible if the 662 // Remember the certificate as it will no longer be accessible if the
562 // handshake fails. 663 // handshake fails.
563 that->UpdateServerCert(); 664 scoped_refptr<X509Certificate> cert = that->UpdateServerCert();
564 665
565 return SSL_AuthCertificate(CERT_GetDefaultCertDB(), socket, checksig, 666 SECStatus rv = SSL_AuthCertificate(CERT_GetDefaultCertDB(), socket, checksig,
566 is_server); 667 is_server);
668 if (rv == SECSuccess && that->cert_list_) {
669 // Remember the intermediate CA certs if the server sends them to us.
670 for (CERTCertListNode* node = CERT_LIST_HEAD(that->cert_list_);
671 !CERT_LIST_END(node, that->cert_list_);
672 node = CERT_LIST_NEXT(node)) {
673 if (node->cert->slot || node->cert->isRoot || node->cert->isperm ||
674 node->cert == cert->os_cert_handle()) {
675 // Some certs we don't want to remember are:
676 // - found on a token.
677 // - the root cert.
678 // - already stored in perm db.
679 // - the server cert itself.
680 continue;
681 }
682
683 // We have found a CA cert that we want to remember.
684 std::string nickname(GetDefaultCertNickname(node->cert));
685 if (!nickname.empty()) {
686 PK11SlotInfo* slot = PK11_GetInternalKeySlot();
687 if (slot) {
688 PK11_ImportCert(slot, node->cert, CK_INVALID_HANDLE,
689 const_cast<char*>(nickname.c_str()), PR_FALSE);
690 PK11_FreeSlot(slot);
691 }
692 }
693 }
694 }
695
696 return rv;
567 } 697 }
568 698
569 // static 699 // static
570 // NSS calls this if an incoming certificate is invalid. 700 // NSS calls this if an incoming certificate is invalid.
571 SECStatus SSLClientSocketNSS::OwnBadCertHandler(void* arg, 701 SECStatus SSLClientSocketNSS::OwnBadCertHandler(void* arg,
572 PRFileDesc* socket) { 702 PRFileDesc* socket) {
573 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); 703 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg);
574 704
575 if (that->server_cert_ && 705 if (that->server_cert_ &&
576 that->ssl_config_.allowed_bad_certs_.count(that->server_cert_)) { 706 that->ssl_config_.allowed_bad_certs_.count(that->server_cert_)) {
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 if (prerr == PR_WOULD_BLOCK_ERROR) { 780 if (prerr == PR_WOULD_BLOCK_ERROR) {
651 GotoState(STATE_PAYLOAD_WRITE); 781 GotoState(STATE_PAYLOAD_WRITE);
652 return ERR_IO_PENDING; 782 return ERR_IO_PENDING;
653 } 783 }
654 user_buf_ = NULL; 784 user_buf_ = NULL;
655 LeaveFunction(""); 785 LeaveFunction("");
656 return NetErrorFromNSPRError(prerr); 786 return NetErrorFromNSPRError(prerr);
657 } 787 }
658 788
659 } // namespace net 789 } // namespace net
OLDNEW
« no previous file with comments | « net/base/ssl_client_socket_nss.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698