client_cert_store_nss.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/ssl/client_cert_store_nss.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <nss.h> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <ssl.h> 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/bind.h" 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/location.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/threading/worker_pool.h" 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "crypto/crypto_module_blocking_password_delegate.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace net { 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Examines the certificates in |cert_list| to find all certificates that match 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// the client certificate request in |request|, storing the matching 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// certificates in |selected_certs|. 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// If |query_nssdb| is true, NSS will be queried to construct full certificate 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// chains. If it is false, only the certificate will be considered. 271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void GetClientCertsImpl(CERTCertList* cert_list, 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SSLCertRequestInfo& request, 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool query_nssdb, 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CertificateList* selected_certs) { 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(cert_list); 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(selected_certs); 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selected_certs->clear(); 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Create a "fake" CERTDistNames structure. No public API exists to create 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // one from a list of issuers. 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CERTDistNames ca_names; 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.arena = NULL; 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.nnames = 0; 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.names = NULL; 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.head = NULL; 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<SECItem> ca_names_items(request.cert_authorities.size()); 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < request.cert_authorities.size(); ++i) { 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& authority = request.cert_authorities[i]; 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names_items[i].type = siBuffer; 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names_items[i].data = 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) reinterpret_cast<unsigned char*>(const_cast<char*>(authority.data())); 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names_items[i].len = static_cast<unsigned int>(authority.size()); 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.nnames = static_cast<int>(ca_names_items.size()); 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!ca_names_items.empty()) 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.names = &ca_names_items[0]; 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !CERT_LIST_END(node, cert_list); 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) node = CERT_LIST_NEXT(node)) { 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Only offer unexpired certificates. 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (CERT_CheckCertValidTimes(node->cert, PR_Now(), PR_TRUE) != 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) secCertTimeValid) { 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) node->cert, X509Certificate::OSCertHandles()); 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check if the certificate issuer is allowed by the server. 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (request.cert_authorities.empty() || 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (!query_nssdb && 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cert->IsIssuedByEncoded(request.cert_authorities)) || 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (query_nssdb && 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NSS_CmpCertChainWCANames(node->cert, &ca_names) == SECSuccess)) { 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) selected_certs->push_back(cert); 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::sort(selected_certs->begin(), selected_certs->end(), 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) x509_util::ClientCertSorter()); 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void GetClientCertsOnWorkerThread( 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_ptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate, 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SSLCertRequestInfo* request, 85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CertificateList* selected_certs) { 86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CERTCertList* client_certs = CERT_FindUserCertsByUsage( 87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CERT_GetDefaultCertDB(), 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) certUsageSSLClient, 89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) PR_FALSE, 90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) PR_FALSE, 91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) password_delegate.get()); 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // It is ok for a user not to have any client certs. 93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!client_certs) { 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) selected_certs->clear(); 95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GetClientCertsImpl(client_certs, *request, true, selected_certs); 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CERT_DestroyCertList(client_certs); 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ClientCertStoreNSS::ClientCertStoreNSS( 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const PasswordDelegateFactory& password_delegate_factory) 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : password_delegate_factory_(password_delegate_factory) {} 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ClientCertStoreNSS::~ClientCertStoreNSS() {} 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ClientCertStoreNSS::GetClientCerts(const SSLCertRequestInfo& request, 1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CertificateList* selected_certs, 1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const base::Closure& callback) { 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_ptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate; 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!password_delegate_factory_.is_null()) { 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) password_delegate.reset( 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) password_delegate_factory_.Run(request.host_and_port)); 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!base::WorkerPool::PostTaskAndReply( 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) FROM_HERE, 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Bind(&GetClientCertsOnWorkerThread, 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Passed(&password_delegate), 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &request, 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) selected_certs), 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) callback, 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) true)) { 1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) selected_certs->clear(); 1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) callback.Run(); 1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ClientCertStoreNSS::SelectClientCertsForTesting( 132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const CertificateList& input_certs, 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const SSLCertRequestInfo& request, 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CertificateList* selected_certs) { 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CERTCertList* cert_list = CERT_NewCertList(); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!cert_list) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < input_certs.size(); ++i) { 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CERT_AddCertToListTail( 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cert_list, CERT_DupCertificate(input_certs[i]->os_cert_handle())); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) GetClientCertsImpl(cert_list, request, false, selected_certs); 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CERT_DestroyCertList(cert_list); 1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return true; 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace net 149