1 // Copyright 2013 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/ssl/client_cert_store_nss.h" 6 7 #include <nss.h> 8 #include <ssl.h> 9 10 #include "base/bind.h" 11 #include "base/location.h" 12 #include "base/logging.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/strings/string_piece.h" 15 #include "base/threading/worker_pool.h" 16 #include "crypto/nss_crypto_module_delegate.h" 17 #include "net/cert/x509_util.h" 18 19 namespace net { 20 21 ClientCertStoreNSS::ClientCertStoreNSS( 22 const PasswordDelegateFactory& password_delegate_factory) 23 : password_delegate_factory_(password_delegate_factory) {} 24 25 ClientCertStoreNSS::~ClientCertStoreNSS() {} 26 27 void ClientCertStoreNSS::GetClientCerts(const SSLCertRequestInfo& request, 28 CertificateList* selected_certs, 29 const base::Closure& callback) { 30 scoped_ptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate; 31 if (!password_delegate_factory_.is_null()) { 32 password_delegate.reset( 33 password_delegate_factory_.Run(request.host_and_port)); 34 } 35 if (base::WorkerPool::PostTaskAndReply( 36 FROM_HERE, 37 base::Bind(&ClientCertStoreNSS::GetClientCertsOnWorkerThread, 38 // Caller is responsible for keeping the ClientCertStore 39 // alive until the callback is run. 40 base::Unretained(this), 41 base::Passed(&password_delegate), 42 &request, 43 selected_certs), 44 callback, 45 true)) 46 return; 47 selected_certs->clear(); 48 callback.Run(); 49 } 50 51 void ClientCertStoreNSS::GetClientCertsImpl(CERTCertList* cert_list, 52 const SSLCertRequestInfo& request, 53 bool query_nssdb, 54 CertificateList* selected_certs) { 55 DCHECK(cert_list); 56 DCHECK(selected_certs); 57 58 selected_certs->clear(); 59 60 // Create a "fake" CERTDistNames structure. No public API exists to create 61 // one from a list of issuers. 62 CERTDistNames ca_names; 63 ca_names.arena = NULL; 64 ca_names.nnames = 0; 65 ca_names.names = NULL; 66 ca_names.head = NULL; 67 68 std::vector<SECItem> ca_names_items(request.cert_authorities.size()); 69 for (size_t i = 0; i < request.cert_authorities.size(); ++i) { 70 const std::string& authority = request.cert_authorities[i]; 71 ca_names_items[i].type = siBuffer; 72 ca_names_items[i].data = 73 reinterpret_cast<unsigned char*>(const_cast<char*>(authority.data())); 74 ca_names_items[i].len = static_cast<unsigned int>(authority.size()); 75 } 76 ca_names.nnames = static_cast<int>(ca_names_items.size()); 77 if (!ca_names_items.empty()) 78 ca_names.names = &ca_names_items[0]; 79 80 size_t num_raw = 0; 81 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); 82 !CERT_LIST_END(node, cert_list); 83 node = CERT_LIST_NEXT(node)) { 84 ++num_raw; 85 // Only offer unexpired certificates. 86 if (CERT_CheckCertValidTimes(node->cert, PR_Now(), PR_TRUE) != 87 secCertTimeValid) { 88 DVLOG(2) << "skipped expired cert: " 89 << base::StringPiece(node->cert->nickname); 90 continue; 91 } 92 93 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( 94 node->cert, X509Certificate::OSCertHandles()); 95 96 // Check if the certificate issuer is allowed by the server. 97 if (request.cert_authorities.empty() || 98 (!query_nssdb && 99 cert->IsIssuedByEncoded(request.cert_authorities)) || 100 (query_nssdb && 101 NSS_CmpCertChainWCANames(node->cert, &ca_names) == SECSuccess)) { 102 DVLOG(2) << "matched cert: " << base::StringPiece(node->cert->nickname); 103 selected_certs->push_back(cert); 104 } 105 else 106 DVLOG(2) << "skipped non-matching cert: " 107 << base::StringPiece(node->cert->nickname); 108 } 109 DVLOG(2) << "num_raw:" << num_raw 110 << " num_selected:" << selected_certs->size(); 111 112 std::sort(selected_certs->begin(), selected_certs->end(), 113 x509_util::ClientCertSorter()); 114 } 115 116 void ClientCertStoreNSS::GetClientCertsOnWorkerThread( 117 scoped_ptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate, 118 const SSLCertRequestInfo* request, 119 CertificateList* selected_certs) { 120 CERTCertList* client_certs = CERT_FindUserCertsByUsage( 121 CERT_GetDefaultCertDB(), 122 certUsageSSLClient, 123 PR_FALSE, 124 PR_FALSE, 125 password_delegate.get()); 126 // It is ok for a user not to have any client certs. 127 if (!client_certs) { 128 DVLOG(2) << "No client certs found."; 129 selected_certs->clear(); 130 return; 131 } 132 133 GetClientCertsImpl(client_certs, *request, true, selected_certs); 134 CERT_DestroyCertList(client_certs); 135 } 136 137 bool ClientCertStoreNSS::SelectClientCertsForTesting( 138 const CertificateList& input_certs, 139 const SSLCertRequestInfo& request, 140 CertificateList* selected_certs) { 141 CERTCertList* cert_list = CERT_NewCertList(); 142 if (!cert_list) 143 return false; 144 for (size_t i = 0; i < input_certs.size(); ++i) { 145 CERT_AddCertToListTail( 146 cert_list, CERT_DupCertificate(input_certs[i]->os_cert_handle())); 147 } 148 149 GetClientCertsImpl(cert_list, request, false, selected_certs); 150 CERT_DestroyCertList(cert_list); 151 return true; 152 } 153 154 } // namespace net 155