OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |