client_cert_store_nss.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_piece.h" 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/threading/worker_pool.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "crypto/nss_crypto_module_delegate.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace net { 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ClientCertStoreNSS::ClientCertStoreNSS( 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const PasswordDelegateFactory& password_delegate_factory) 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : password_delegate_factory_(password_delegate_factory) {} 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ClientCertStoreNSS::~ClientCertStoreNSS() {} 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ClientCertStoreNSS::GetClientCerts(const SSLCertRequestInfo& request, 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CertificateList* selected_certs, 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::Closure& callback) { 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate; 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!password_delegate_factory_.is_null()) { 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) password_delegate.reset( 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) password_delegate_factory_.Run(request.host_and_port)); 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (base::WorkerPool::PostTaskAndReply( 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&ClientCertStoreNSS::GetClientCertsOnWorkerThread, 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Caller is responsible for keeping the ClientCertStore 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // alive until the callback is run. 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(this), 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Passed(&password_delegate), 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &request, 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) selected_certs), 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback, 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) true)) 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) selected_certs->clear(); 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(); 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ClientCertStoreNSS::GetClientCertsImpl(CERTCertList* cert_list, 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const SSLCertRequestInfo& request, 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool query_nssdb, 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CertificateList* selected_certs) { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(cert_list); 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(selected_certs); 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selected_certs->clear(); 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Create a "fake" CERTDistNames structure. No public API exists to create 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // one from a list of issuers. 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CERTDistNames ca_names; 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.arena = NULL; 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.nnames = 0; 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.names = NULL; 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.head = NULL; 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<SECItem> ca_names_items(request.cert_authorities.size()); 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (size_t i = 0; i < request.cert_authorities.size(); ++i) { 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& authority = request.cert_authorities[i]; 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names_items[i].type = siBuffer; 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names_items[i].data = 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) reinterpret_cast<unsigned char*>(const_cast<char*>(authority.data())); 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names_items[i].len = static_cast<unsigned int>(authority.size()); 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.nnames = static_cast<int>(ca_names_items.size()); 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!ca_names_items.empty()) 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ca_names.names = &ca_names_items[0]; 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t num_raw = 0; 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !CERT_LIST_END(node, cert_list); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) node = CERT_LIST_NEXT(node)) { 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++num_raw; 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Only offer unexpired certificates. 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (CERT_CheckCertValidTimes(node->cert, PR_Now(), PR_TRUE) != 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) secCertTimeValid) { 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DVLOG(2) << "skipped expired cert: " 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << base::StringPiece(node->cert->nickname); 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) node->cert, X509Certificate::OSCertHandles()); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check if the certificate issuer is allowed by the server. 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (request.cert_authorities.empty() || 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (!query_nssdb && 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cert->IsIssuedByEncoded(request.cert_authorities)) || 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (query_nssdb && 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NSS_CmpCertChainWCANames(node->cert, &ca_names) == SECSuccess)) { 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DVLOG(2) << "matched cert: " << base::StringPiece(node->cert->nickname); 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) selected_certs->push_back(cert); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DVLOG(2) << "skipped non-matching cert: " 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << base::StringPiece(node->cert->nickname); 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DVLOG(2) << "num_raw:" << num_raw 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) << " num_selected:" << selected_certs->size(); 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::sort(selected_certs->begin(), selected_certs->end(), 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) x509_util::ClientCertSorter()); 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ClientCertStoreNSS::GetClientCertsOnWorkerThread( 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_ptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate, 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SSLCertRequestInfo* request, 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CertificateList* selected_certs) { 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CERTCertList* client_certs = CERT_FindUserCertsByUsage( 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CERT_GetDefaultCertDB(), 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) certUsageSSLClient, 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) PR_FALSE, 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) PR_FALSE, 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) password_delegate.get()); 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // It is ok for a user not to have any client certs. 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!client_certs) { 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DVLOG(2) << "No client certs found."; 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) selected_certs->clear(); 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GetClientCertsImpl(client_certs, *request, true, selected_certs); 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CERT_DestroyCertList(client_certs); 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ClientCertStoreNSS::SelectClientCertsForTesting( 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const CertificateList& input_certs, 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const SSLCertRequestInfo& request, 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CertificateList* selected_certs) { 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CERTCertList* cert_list = CERT_NewCertList(); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!cert_list) 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < input_certs.size(); ++i) { 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CERT_AddCertToListTail( 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cert_list, CERT_DupCertificate(input_certs[i]->os_cert_handle())); 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) GetClientCertsImpl(cert_list, request, false, selected_certs); 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CERT_DestroyCertList(cert_list); 1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return true; 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace net 155