| // Copyright 2023 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "remoting/base/certificate_helpers.h" | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "base/logging.h" | 
 | #include "build/build_config.h" | 
 | #include "crypto/crypto_buildflags.h" | 
 | #include "net/cert/x509_certificate.h" | 
 | #include "net/ssl/client_cert_store.h" | 
 |  | 
 | #if BUILDFLAG(USE_NSS_CERTS) | 
 | #include "net/ssl/client_cert_store_nss.h" | 
 | #elif BUILDFLAG(IS_WIN) | 
 | #include "net/ssl/client_cert_store_win.h" | 
 | #elif BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_IOS) | 
 | #include "net/ssl/client_cert_store_mac.h" | 
 | #endif | 
 |  | 
 | namespace remoting { | 
 |  | 
 | namespace { | 
 |  | 
 | constexpr char kCertIssuerWildCard[] = "*"; | 
 |  | 
 | // Returns true if certificate |c1| is a worse match than |c2|. | 
 | // | 
 | // Criteria: | 
 | // 1. An invalid certificate is always worse than a valid certificate. | 
 | // 2. Invalid certificates are equally bad, in which case false will be | 
 | //    returned. | 
 | // 3. A certificate with earlier |valid_start| time is worse. | 
 | // 4. When |valid_start| are the same, the certificate with earlier | 
 | //    |valid_expiry| is worse. | 
 | bool WorseThan(const std::string& issuer, | 
 |                const base::Time& now, | 
 |                const net::X509Certificate& c1, | 
 |                const net::X509Certificate& c2) { | 
 |   if (!IsCertificateValid(issuer, now, c2)) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   if (!IsCertificateValid(issuer, now, c1)) { | 
 |     return true; | 
 |   } | 
 |  | 
 |   if (c1.valid_start() != c2.valid_start()) { | 
 |     return c1.valid_start() < c2.valid_start(); | 
 |   } | 
 |  | 
 |   return c1.valid_expiry() < c2.valid_expiry(); | 
 | } | 
 |  | 
 | #if BUILDFLAG(IS_WIN) | 
 | crypto::ScopedHCERTSTORE OpenLocalMachineCertStore() { | 
 |   return crypto::ScopedHCERTSTORE(::CertOpenStore( | 
 |       CERT_STORE_PROV_SYSTEM, 0, NULL, | 
 |       CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG, L"MY")); | 
 | } | 
 | #endif | 
 |  | 
 | }  // namespace | 
 |  | 
 | std::string GetPreferredIssuerFieldValue(const net::X509Certificate& cert) { | 
 |   if (!cert.issuer().common_name.empty()) { | 
 |     return cert.issuer().common_name; | 
 |   } | 
 |   if (!cert.issuer().organization_names.empty() && | 
 |       !cert.issuer().organization_names[0].empty()) { | 
 |     return cert.issuer().organization_names[0]; | 
 |   } | 
 |   if (!cert.issuer().organization_unit_names.empty() && | 
 |       !cert.issuer().organization_unit_names[0].empty()) { | 
 |     return cert.issuer().organization_unit_names[0]; | 
 |   } | 
 |  | 
 |   return std::string(); | 
 | } | 
 |  | 
 | bool IsCertificateValid(const std::string& issuer, | 
 |                         const base::Time& now, | 
 |                         const net::X509Certificate& cert) { | 
 |   return (issuer == kCertIssuerWildCard || | 
 |           issuer == GetPreferredIssuerFieldValue(cert)) && | 
 |          cert.valid_start() <= now && cert.valid_expiry() > now; | 
 | } | 
 |  | 
 | std::unique_ptr<net::ClientCertIdentity> GetBestMatchFromCertificateList( | 
 |     const std::string& issuer, | 
 |     const base::Time& now, | 
 |     net::ClientCertIdentityList& client_certs) { | 
 |   auto best_match_position = std::max_element( | 
 |       client_certs.begin(), client_certs.end(), | 
 |       [&issuer, now](std::unique_ptr<net::ClientCertIdentity>& i1, | 
 |                      std::unique_ptr<net::ClientCertIdentity>& i2) { | 
 |         return WorseThan(issuer, now, *i1->certificate(), *i2->certificate()); | 
 |       }); | 
 |  | 
 |   if (best_match_position == client_certs.end()) { | 
 |     LOG(ERROR) << "Failed to find a certificate from the list of candidates (" | 
 |                << client_certs.size() << ")."; | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   return std::move(*best_match_position); | 
 | } | 
 |  | 
 | std::unique_ptr<net::ClientCertStore> CreateClientCertStoreInstance() { | 
 | #if BUILDFLAG(USE_NSS_CERTS) | 
 |   return std::make_unique<net::ClientCertStoreNSS>( | 
 |       net::ClientCertStoreNSS::PasswordDelegateFactory()); | 
 | #elif BUILDFLAG(IS_WIN) | 
 |   // The network process is running as "Local Service" whose "Current User" | 
 |   // cert store doesn't contain any certificates. Use the "Local Machine" | 
 |   // store instead. | 
 |   // The ACL on the private key of the machine certificate in the "Local | 
 |   // Machine" cert store needs to allow access by "Local Service". | 
 |   return std::make_unique<net::ClientCertStoreWin>( | 
 |       base::BindRepeating(&OpenLocalMachineCertStore)); | 
 | #elif BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_IOS) | 
 |   return std::make_unique<net::ClientCertStoreMac>(); | 
 | #else | 
 |   // OpenSSL does not use the ClientCertStore infrastructure. | 
 |   return nullptr; | 
 | #endif | 
 | } | 
 |  | 
 | }  // namespace remoting |