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