summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorukai@chromium.org <ukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-29 05:55:04 +0000
committerukai@chromium.org <ukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-29 05:55:04 +0000
commitbf0136d62bfe02f57821ce026c04b6e8204eb482 (patch)
treed3e49a114eca52df8f2279851e9f52846275f19b /net
parent32754b5ee0bdece0782c0fdff7bebfc1c01f0865 (diff)
downloadchromium_src-bf0136d62bfe02f57821ce026c04b6e8204eb482.zip
chromium_src-bf0136d62bfe02f57821ce026c04b6e8204eb482.tar.gz
chromium_src-bf0136d62bfe02f57821ce026c04b6e8204eb482.tar.bz2
Remember the intermediate CA certs if the server sends them to us.
BUG=10911 TEST=net_unittests passes Review URL: http://codereview.chromium.org/115700 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17168 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/ssl_client_socket_nss.cc150
-rw-r--r--net/base/ssl_client_socket_nss.h7
2 files changed, 147 insertions, 10 deletions
diff --git a/net/base/ssl_client_socket_nss.cc b/net/base/ssl_client_socket_nss.cc
index a8993a932..12ef11e 100644
--- a/net/base/ssl_client_socket_nss.cc
+++ b/net/base/ssl_client_socket_nss.cc
@@ -2,8 +2,55 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This file includes code GetDefaultCertNickname(), derived from
+// nsNSSCertificate::defaultServerNickName()
+// in mozilla/security/manager/ssl/src/nsNSSCertificate.cpp
+// and SSLClientSocketNSS::OwnAuthCertHandler() derived from
+// AuthCertificateCallback() in
+// mozilla/security/manager/ssl/src/nsNSSCallbacks.cpp.
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Ian McGreer <mcgreer@netscape.com>
+ * Javier Delgadillo <javi@netscape.com>
+ * Kai Engert <kengert@redhat.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
#include "net/base/ssl_client_socket_nss.h"
+#include <certdb.h>
#include <nspr.h>
#include <nss.h>
#include <secerr.h>
@@ -47,6 +94,48 @@ namespace net {
namespace {
+// Gets default certificate nickname from cert.
+// Derived from nsNSSCertificate::defaultServerNickname
+// in mozilla/security/manager/ssl/src/nsNSSCertificate.cpp.
+std::string GetDefaultCertNickname(
+ net::X509Certificate::OSCertHandle cert) {
+ if (cert == NULL)
+ return "";
+
+ char* name = CERT_GetCommonName(&cert->subject);
+ if (!name) {
+ // Certs without common names are strange, but they do exist...
+ // Let's try to use another string for the nickname
+ name = CERT_GetOrgUnitName(&cert->subject);
+ if (!name)
+ name = CERT_GetOrgName(&cert->subject);
+ if (!name)
+ name = CERT_GetLocalityName(&cert->subject);
+ if (!name)
+ name = CERT_GetStateName(&cert->subject);
+ if (!name)
+ name = CERT_GetCountryName(&cert->subject);
+ if (!name)
+ return "";
+ }
+ int count = 1;
+ std::string nickname;
+ while (1) {
+ if (count == 1) {
+ nickname = name;
+ } else {
+ nickname = StringPrintf("%s #%d", name, count);
+ }
+ PRBool conflict = SEC_CertNicknameConflict(
+ const_cast<char*>(nickname.c_str()), &cert->derSubject, cert->dbhandle);
+ if (!conflict)
+ break;
+ count++;
+ }
+ PR_FREEIF(name);
+ return nickname;
+}
+
int NetErrorFromNSPRError(PRErrorCode err) {
// TODO(port): fill this out as we learn what's important
switch (err) {
@@ -108,6 +197,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocket* transport_socket,
user_callback_(NULL),
user_buf_len_(0),
server_cert_error_(0),
+ cert_list_(NULL),
completed_handshake_(false),
next_state_(STATE_NONE),
nss_fd_(NULL),
@@ -270,23 +360,29 @@ void SSLClientSocketNSS::InvalidateSessionIfBadCertificate() {
void SSLClientSocketNSS::Disconnect() {
EnterFunction("");
+ // TODO(wtc): Send SSL close_notify alert.
+ if (nss_fd_ != NULL) {
+ InvalidateSessionIfBadCertificate();
+ PR_Close(nss_fd_);
+ nss_fd_ = NULL;
+ }
+
+ transport_->Disconnect();
+
// Reset object state
transport_send_busy_ = false;
transport_recv_busy_ = false;
user_buf_ = NULL;
user_buf_len_ = 0;
+ server_cert_ = NULL;
server_cert_error_ = OK;
+ if (cert_list_) {
+ CERT_DestroyCertList(cert_list_);
+ cert_list_ = NULL;
+ }
completed_handshake_ = false;
nss_bufs_ = NULL;
- // TODO(wtc): Send SSL close_notify alert.
- if (nss_fd_ != NULL) {
- InvalidateSessionIfBadCertificate();
- PR_Close(nss_fd_);
- nss_fd_ = NULL;
- }
-
- transport_->Disconnect();
LeaveFunction("");
}
@@ -364,6 +460,9 @@ X509Certificate *SSLClientSocketNSS::UpdateServerCert() {
if (nss_cert) {
server_cert_ = X509Certificate::CreateFromHandle(
nss_cert, X509Certificate::SOURCE_FROM_NETWORK);
+ DCHECK(!cert_list_);
+ cert_list_ = CERT_GetCertChainFromCert(
+ nss_cert, PR_Now(), certUsageSSLCA);
}
}
return server_cert_;
@@ -552,6 +651,8 @@ int SSLClientSocketNSS::DoLoop(int last_io_result) {
// static
// NSS calls this if an incoming certificate needs to be verified.
+// Derived from AuthCertificateCallback() in
+// mozilla/source/security/manager/ssl/src/nsNSSCallbacks.cpp.
SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg,
PRFileDesc* socket,
PRBool checksig,
@@ -560,10 +661,39 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg,
// Remember the certificate as it will no longer be accessible if the
// handshake fails.
- that->UpdateServerCert();
+ scoped_refptr<X509Certificate> cert = that->UpdateServerCert();
- return SSL_AuthCertificate(CERT_GetDefaultCertDB(), socket, checksig,
+ SECStatus rv = SSL_AuthCertificate(CERT_GetDefaultCertDB(), socket, checksig,
is_server);
+ if (rv == SECSuccess && that->cert_list_) {
+ // Remember the intermediate CA certs if the server sends them to us.
+ for (CERTCertListNode* node = CERT_LIST_HEAD(that->cert_list_);
+ !CERT_LIST_END(node, that->cert_list_);
+ node = CERT_LIST_NEXT(node)) {
+ if (node->cert->slot || node->cert->isRoot || node->cert->isperm ||
+ node->cert == cert->os_cert_handle()) {
+ // Some certs we don't want to remember are:
+ // - found on a token.
+ // - the root cert.
+ // - already stored in perm db.
+ // - the server cert itself.
+ continue;
+ }
+
+ // We have found a CA cert that we want to remember.
+ std::string nickname(GetDefaultCertNickname(node->cert));
+ if (!nickname.empty()) {
+ PK11SlotInfo* slot = PK11_GetInternalKeySlot();
+ if (slot) {
+ PK11_ImportCert(slot, node->cert, CK_INVALID_HANDLE,
+ const_cast<char*>(nickname.c_str()), PR_FALSE);
+ PK11_FreeSlot(slot);
+ }
+ }
+ }
+ }
+
+ return rv;
}
// static
diff --git a/net/base/ssl_client_socket_nss.h b/net/base/ssl_client_socket_nss.h
index 9dfe5ab..b3b6706 100644
--- a/net/base/ssl_client_socket_nss.h
+++ b/net/base/ssl_client_socket_nss.h
@@ -5,6 +5,11 @@
#ifndef NET_BASE_SSL_CLIENT_SOCKET_NSS_H_
#define NET_BASE_SSL_CLIENT_SOCKET_NSS_H_
+// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
+// until NSS 3.12.2 comes out and we update to it.
+#define Lock FOO_NSS_Lock
+#include <certt.h>
+#undef Lock
#include <nspr.h>
#include <nss.h>
#include <string>
@@ -90,6 +95,8 @@ class SSLClientSocketNSS : public SSLClientSocket {
// Set during handshake.
scoped_refptr<X509Certificate> server_cert_;
+ // Certificate chain.
+ CERTCertList* cert_list_;
bool completed_handshake_;