Home | History | Annotate | Download | only in ssl
      1 // Copyright (c) 2012 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_impl.h"
      6 
      7 #include <nss.h>
      8 #include <ssl.h>
      9 
     10 #include "base/logging.h"
     11 #include "net/cert/x509_util.h"
     12 
     13 namespace net {
     14 
     15 namespace {
     16 
     17 // Examines the certificates in |cert_list| to find all certificates that match
     18 // the client certificate request in |request|, storing the matching
     19 // certificates in |selected_certs|.
     20 // If |query_nssdb| is true, NSS will be queried to construct full certificate
     21 // chains. If it is false, only the certificate will be considered.
     22 bool GetClientCertsImpl(CERTCertList* cert_list,
     23                         const SSLCertRequestInfo& request,
     24                         bool query_nssdb,
     25                         CertificateList* selected_certs) {
     26   DCHECK(cert_list);
     27   DCHECK(selected_certs);
     28 
     29   selected_certs->clear();
     30 
     31   // Create a "fake" CERTDistNames structure. No public API exists to create
     32   // one from a list of issuers.
     33   CERTDistNames ca_names;
     34   ca_names.arena = NULL;
     35   ca_names.nnames = 0;
     36   ca_names.names = NULL;
     37   ca_names.head = NULL;
     38 
     39   std::vector<SECItem> ca_names_items(request.cert_authorities.size());
     40   for (size_t i = 0; i < request.cert_authorities.size(); ++i) {
     41     const std::string& authority = request.cert_authorities[i];
     42     ca_names_items[i].type = siBuffer;
     43     ca_names_items[i].data =
     44         reinterpret_cast<unsigned char*>(const_cast<char*>(authority.data()));
     45     ca_names_items[i].len = static_cast<unsigned int>(authority.size());
     46   }
     47   ca_names.nnames = static_cast<int>(ca_names_items.size());
     48   if (!ca_names_items.empty())
     49     ca_names.names = &ca_names_items[0];
     50 
     51   for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
     52        !CERT_LIST_END(node, cert_list);
     53        node = CERT_LIST_NEXT(node)) {
     54     // Only offer unexpired certificates.
     55     if (CERT_CheckCertValidTimes(node->cert, PR_Now(), PR_TRUE) !=
     56         secCertTimeValid) {
     57       continue;
     58     }
     59 
     60     scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
     61         node->cert, X509Certificate::OSCertHandles());
     62 
     63     // Check if the certificate issuer is allowed by the server.
     64     if (request.cert_authorities.empty() ||
     65         (!query_nssdb &&
     66          cert->IsIssuedByEncoded(request.cert_authorities)) ||
     67         (query_nssdb &&
     68          NSS_CmpCertChainWCANames(node->cert, &ca_names) == SECSuccess)) {
     69       selected_certs->push_back(cert);
     70     }
     71   }
     72 
     73   std::sort(selected_certs->begin(), selected_certs->end(),
     74             x509_util::ClientCertSorter());
     75   return true;
     76 }
     77 
     78 }  // namespace
     79 
     80 bool ClientCertStoreImpl::GetClientCerts(const SSLCertRequestInfo& request,
     81                                          CertificateList* selected_certs) {
     82   CERTCertList* client_certs = CERT_FindUserCertsByUsage(
     83       CERT_GetDefaultCertDB(), certUsageSSLClient,
     84       PR_FALSE, PR_FALSE, NULL);
     85   // It is ok for a user not to have any client certs.
     86   if (!client_certs)
     87     return true;
     88 
     89   bool rv = GetClientCertsImpl(client_certs, request, true, selected_certs);
     90   CERT_DestroyCertList(client_certs);
     91   return rv;
     92 }
     93 
     94 bool ClientCertStoreImpl::SelectClientCertsForTesting(
     95     const CertificateList& input_certs,
     96     const SSLCertRequestInfo& request,
     97     CertificateList* selected_certs) {
     98   CERTCertList* cert_list = CERT_NewCertList();
     99   if (!cert_list)
    100     return false;
    101   for (size_t i = 0; i < input_certs.size(); ++i) {
    102     CERT_AddCertToListTail(
    103         cert_list, CERT_DupCertificate(input_certs[i]->os_cert_handle()));
    104   }
    105 
    106   bool rv = GetClientCertsImpl(cert_list, request, false, selected_certs);
    107   CERT_DestroyCertList(cert_list);
    108   return rv;
    109 }
    110 
    111 }  // namespace net
    112