Make ChromeOS certificate code use NSS types directly.

Bug: 671420, 736159
Change-Id: Ic480cf5dedc644294b4f11737f3f151243febce6
Reviewed-on: https://chromium-review.googlesource.com/621489
Reviewed-by: Lei Zhang <[email protected]>
Reviewed-by: Steven Bennetts <[email protected]>
Reviewed-by: David Benjamin <[email protected]>
Commit-Queue: Matt Mueller <[email protected]>
Cr-Commit-Position: refs/heads/master@{#500334}
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index 1cf49d7..c9e9c827 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -210,8 +210,8 @@
           x509_certificate_model::GetSerialNumberHexified(cert, std::string()));
       break;
     case COL_EXPIRES_ON: {
-      base::Time not_before, not_after;
-      if (net::x509_util::GetValidityTimes(cert, &not_before, &not_after))
+      base::Time not_after;
+      if (net::x509_util::GetValidityTimes(cert, nullptr, &not_after))
         rv = base::TimeFormatShortDateNumeric(not_after);
       break;
     }
diff --git a/chrome/browser/chromeos/options/cert_library.cc b/chrome/browser/chromeos/options/cert_library.cc
index dad898a0..e060790 100644
--- a/chrome/browser/chromeos/options/cert_library.cc
+++ b/chrome/browser/chromeos/options/cert_library.cc
@@ -21,6 +21,7 @@
 #include "crypto/nss_util.h"
 #include "net/cert/cert_database.h"
 #include "net/cert/nss_cert_database.h"
+#include "net/cert/x509_util_nss.h"
 #include "third_party/icu/source/i18n/unicode/coll.h"  // icu::Collator
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_collator.h"
@@ -32,20 +33,14 @@
 // Root CA certificates that are built into Chrome use this token name.
 const char kRootCertificateTokenName[] = "Builtin Object Token";
 
-base::string16 GetDisplayString(net::X509Certificate* cert,
-                                bool hardware_backed) {
-  std::string alt_text;
-  if (!cert->subject().organization_names.empty())
-    alt_text = cert->subject().organization_names[0];
-  if (alt_text.empty())
-    alt_text = cert->subject().GetDisplayName();
-  base::string16 issued_by = base::UTF8ToUTF16(
-      certificate::GetIssuerCommonName(cert->os_cert_handle(), alt_text));
+base::string16 GetDisplayString(CERTCertificate* cert, bool hardware_backed) {
+  base::string16 issued_by =
+      base::UTF8ToUTF16(certificate::GetIssuerDisplayName(cert));
 
-  base::string16 issued_to = base::UTF8ToUTF16(
-      certificate::GetCertNameOrNickname(cert->os_cert_handle()));
-  base::string16 issued_to_ascii = base::UTF8ToUTF16(
-      certificate::GetCertAsciiNameOrNickname(cert->os_cert_handle()));
+  base::string16 issued_to =
+      base::UTF8ToUTF16(certificate::GetCertNameOrNickname(cert));
+  base::string16 issued_to_ascii =
+      base::UTF8ToUTF16(certificate::GetCertAsciiNameOrNickname(cert));
   if (issued_to_ascii != issued_to) {
     // Input contained encoded data, show original and decoded forms.
     issued_to = l10n_util::GetStringFUTF16(IDS_CERT_INFO_IDN_VALUE_FORMAT,
@@ -66,10 +61,9 @@
   }
 }
 
-std::string CertToPEM(const net::X509Certificate& cert) {
+std::string CertToPEM(CERTCertificate* cert) {
   std::string pem_encoded_cert;
-  if (!net::X509Certificate::GetPEMEncoded(cert.os_cert_handle(),
-                                           &pem_encoded_cert)) {
+  if (!net::x509_util::GetPEMEncoded(cert, &pem_encoded_cert)) {
     LOG(ERROR) << "Couldn't PEM-encode certificate";
     return std::string();
   }
@@ -84,8 +78,8 @@
       : collator_(collator) {
   }
 
-  bool operator()(const scoped_refptr<net::X509Certificate>& lhs,
-                  const scoped_refptr<net::X509Certificate>& rhs) const {
+  bool operator()(const net::ScopedCERTCertificate& lhs,
+                  const net::ScopedCERTCertificate& rhs) const {
     base::string16 lhs_name = GetDisplayString(lhs.get(), false);
     base::string16 rhs_name = GetDisplayString(rhs.get(), false);
     if (collator_ == NULL)
@@ -149,28 +143,29 @@
 }
 
 int CertLibrary::NumCertificates(CertType type) const {
-  const net::CertificateList& cert_list = GetCertificateListForType(type);
+  const net::ScopedCERTCertificateList& cert_list =
+      GetCertificateListForType(type);
   return static_cast<int>(cert_list.size());
 }
 
 base::string16 CertLibrary::GetCertDisplayStringAt(CertType type,
                                                    int index) const {
-  net::X509Certificate* cert = GetCertificateAt(type, index);
+  CERTCertificate* cert = GetCertificateAt(type, index);
   bool hardware_backed = IsCertHardwareBackedAt(type, index);
   return GetDisplayString(cert, hardware_backed);
 }
 
 std::string CertLibrary::GetServerCACertPEMAt(int index) const {
-  return CertToPEM(*GetCertificateAt(CERT_TYPE_SERVER_CA, index));
+  return CertToPEM(GetCertificateAt(CERT_TYPE_SERVER_CA, index));
 }
 
 std::string CertLibrary::GetUserCertPkcs11IdAt(int index, int* slot_id) const {
-  net::X509Certificate* cert = GetCertificateAt(CERT_TYPE_USER, index);
-  return CertLoader::GetPkcs11IdAndSlotForCert(*cert, slot_id);
+  CERTCertificate* cert = GetCertificateAt(CERT_TYPE_USER, index);
+  return CertLoader::GetPkcs11IdAndSlotForCert(cert, slot_id);
 }
 
 bool CertLibrary::IsCertHardwareBackedAt(CertType type, int index) const {
-  net::X509Certificate* cert = GetCertificateAt(type, index);
+  CERTCertificate* cert = GetCertificateAt(type, index);
   return CertLoader::IsCertificateHardwareBacked(cert);
 }
 
@@ -178,8 +173,8 @@
     const std::string& pem_encoded) const {
   int num_certs = NumCertificates(CERT_TYPE_SERVER_CA);
   for (int index = 0; index < num_certs; ++index) {
-    net::X509Certificate* cert = GetCertificateAt(CERT_TYPE_SERVER_CA, index);
-    if (CertToPEM(*cert) != pem_encoded)
+    CERTCertificate* cert = GetCertificateAt(CERT_TYPE_SERVER_CA, index);
+    if (CertToPEM(cert) != pem_encoded)
       continue;
     return index;
   }
@@ -190,17 +185,18 @@
     const std::string& pkcs11_id) const {
   int num_certs = NumCertificates(CERT_TYPE_USER);
   for (int index = 0; index < num_certs; ++index) {
-    net::X509Certificate* cert = GetCertificateAt(CERT_TYPE_USER, index);
+    CERTCertificate* cert = GetCertificateAt(CERT_TYPE_USER, index);
     int slot_id = -1;
-    std::string id = CertLoader::GetPkcs11IdAndSlotForCert(*cert, &slot_id);
+    std::string id = CertLoader::GetPkcs11IdAndSlotForCert(cert, &slot_id);
     if (id == pkcs11_id)
       return index;
   }
   return -1;  // Not found.
 }
 
-void CertLibrary::OnCertificatesLoaded(const net::CertificateList& cert_list,
-                                       bool initial_load) {
+void CertLibrary::OnCertificatesLoaded(
+    const net::ScopedCERTCertificateList& cert_list,
+    bool initial_load) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   VLOG(1) << "CertLibrary::OnCertificatesLoaded: " << cert_list.size();
   certs_.clear();
@@ -209,24 +205,23 @@
   server_ca_certs_.clear();
 
   // Add certificates to the appropriate list.
-  for (net::CertificateList::const_iterator iter = cert_list.begin();
-       iter != cert_list.end(); ++iter) {
-    certs_.push_back(iter->get());
-    net::X509Certificate::OSCertHandle cert_handle =
-        iter->get()->os_cert_handle();
-    net::CertType type = certificate::GetCertType(cert_handle);
+  certs_.reserve(cert_list.size());
+  for (const net::ScopedCERTCertificate& cert : cert_list) {
+    certs_.push_back(net::x509_util::DupCERTCertificate(cert.get()));
+    net::CertType type = certificate::GetCertType(cert.get());
     switch (type) {
       case net::USER_CERT:
-        user_certs_.push_back(iter->get());
+        user_certs_.push_back(net::x509_util::DupCERTCertificate(cert.get()));
         break;
       case net::SERVER_CERT:
-        server_certs_.push_back(iter->get());
+        server_certs_.push_back(net::x509_util::DupCERTCertificate(cert.get()));
         break;
       case net::CA_CERT: {
         // Exclude root CA certificates that are built into Chrome.
-        std::string token_name = certificate::GetCertTokenName(cert_handle);
+        std::string token_name = certificate::GetCertTokenName(cert.get());
         if (token_name != kRootCertificateTokenName)
-          server_ca_certs_.push_back(iter->get());
+          server_ca_certs_.push_back(
+              net::x509_util::DupCERTCertificate(cert.get()));
         break;
       }
       default:
@@ -256,15 +251,15 @@
     observer.OnCertificatesLoaded(initial_load);
 }
 
-net::X509Certificate* CertLibrary::GetCertificateAt(CertType type,
-                                                    int index) const {
-  const net::CertificateList& cert_list = GetCertificateListForType(type);
+CERTCertificate* CertLibrary::GetCertificateAt(CertType type, int index) const {
+  const net::ScopedCERTCertificateList& cert_list =
+      GetCertificateListForType(type);
   DCHECK_GE(index, 0);
   DCHECK_LT(index, static_cast<int>(cert_list.size()));
   return cert_list[index].get();
 }
 
-const net::CertificateList& CertLibrary::GetCertificateListForType(
+const net::ScopedCERTCertificateList& CertLibrary::GetCertificateListForType(
     CertType type) const {
   if (type == CERT_TYPE_USER)
     return user_certs_;
diff --git a/chrome/browser/chromeos/options/cert_library.h b/chrome/browser/chromeos/options/cert_library.h
index 49b8e1a..a17dd04 100644
--- a/chrome/browser/chromeos/options/cert_library.h
+++ b/chrome/browser/chromeos/options/cert_library.h
@@ -11,7 +11,7 @@
 #include "base/strings/string16.h"
 #include "base/threading/thread_checker.h"
 #include "chromeos/cert_loader.h"
-#include "net/cert/x509_certificate.h"
+#include "net/cert/scoped_nss_types.h"
 
 namespace chromeos {
 
@@ -79,23 +79,24 @@
   int GetUserCertIndexByPkcs11Id(const std::string& pkcs11_id) const;
 
   // CertLoader::Observer
-  void OnCertificatesLoaded(const net::CertificateList&,
+  void OnCertificatesLoaded(const net::ScopedCERTCertificateList&,
                             bool initial_load) override;
 
  private:
   CertLibrary();
   ~CertLibrary() override;
 
-  net::X509Certificate* GetCertificateAt(CertType type, int index) const;
-  const net::CertificateList& GetCertificateListForType(CertType type) const;
+  CERTCertificate* GetCertificateAt(CertType type, int index) const;
+  const net::ScopedCERTCertificateList& GetCertificateListForType(
+      CertType type) const;
 
   base::ObserverList<CertLibrary::Observer> observer_list_;
 
   // Sorted certificate lists
-  net::CertificateList certs_;
-  net::CertificateList user_certs_;
-  net::CertificateList server_certs_;
-  net::CertificateList server_ca_certs_;
+  net::ScopedCERTCertificateList certs_;
+  net::ScopedCERTCertificateList user_certs_;
+  net::ScopedCERTCertificateList server_certs_;
+  net::ScopedCERTCertificateList server_ca_certs_;
 
   THREAD_CHECKER(thread_checker_);
 
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
index ec306f0..81c8c05 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
@@ -36,13 +36,19 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "crypto/nss_key_util.h"
+#include "crypto/openssl_util.h"
 #include "crypto/scoped_nss_types.h"
 #include "net/base/net_errors.h"
+#include "net/cert/asn1_util.h"
 #include "net/cert/cert_database.h"
 #include "net/cert/nss_cert_database.h"
 #include "net/cert/x509_util_nss.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/rsa.h"
 
 using content::BrowserContext;
 using content::BrowserThread;
@@ -268,7 +274,7 @@
         from, base::Bind(callback_, base::Passed(&certs), error_message));
   }
 
-  std::unique_ptr<net::CertificateList> certs_;
+  net::ScopedCERTCertificateList certs_;
 
  private:
   // Must be called on origin thread, therefore use CallBack().
@@ -581,10 +587,10 @@
 void FilterCertificatesOnWorkerThread(
     std::unique_ptr<GetCertificatesState> state) {
   std::unique_ptr<net::CertificateList> client_certs(new net::CertificateList);
-  for (net::CertificateList::const_iterator it = state->certs_->begin();
-       it != state->certs_->end();
-       ++it) {
-    net::X509Certificate::OSCertHandle cert_handle = (*it)->os_cert_handle();
+  for (net::ScopedCERTCertificateList::const_iterator it =
+           state->certs_.begin();
+       it != state->certs_.end(); ++it) {
+    CERTCertificate* cert_handle = it->get();
     crypto::ScopedPK11Slot cert_slot(PK11_KeyForCertExists(cert_handle,
                                                            NULL,    // keyPtr
                                                            NULL));  // wincx
@@ -594,7 +600,12 @@
     if (cert_slot != state->slot_)
       continue;
 
-    client_certs->push_back(*it);
+    scoped_refptr<net::X509Certificate> cert =
+        net::x509_util::CreateX509CertificateFromCERTCertificate(cert_handle);
+    if (!cert)
+      continue;
+
+    client_certs->push_back(std::move(cert));
   }
 
   state->CallBack(FROM_HERE, std::move(client_certs),
@@ -604,7 +615,7 @@
 // Passes the obtained certificates to the worker thread for filtering. Used by
 // GetCertificatesWithDB().
 void DidGetCertificates(std::unique_ptr<GetCertificatesState> state,
-                        std::unique_ptr<net::CertificateList> all_certs) {
+                        net::ScopedCERTCertificateList all_certs) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   state->certs_ = std::move(all_certs);
   // This task interacts with the TPM, hence MayBlock().
@@ -641,16 +652,24 @@
     return;
   }
 
+  net::ScopedCERTCertificate nss_cert =
+      net::x509_util::CreateCERTCertificateFromX509Certificate(
+          state->certificate_.get());
+  if (!nss_cert) {
+    state->OnError(FROM_HERE, net::ErrorToString(net::ERR_CERT_INVALID));
+    return;
+  }
+
   // Check that the private key is in the correct slot.
   crypto::ScopedPK11Slot slot(
-      PK11_KeyForCertExists(state->certificate_->os_cert_handle(), NULL, NULL));
+      PK11_KeyForCertExists(nss_cert.get(), NULL, NULL));
   if (slot.get() != state->slot_.get()) {
     state->OnError(FROM_HERE, kErrorKeyNotFound);
     return;
   }
 
-  const net::Error import_status = static_cast<net::Error>(
-      cert_db->ImportUserCert(state->certificate_.get()));
+  const net::Error import_status =
+      static_cast<net::Error>(cert_db->ImportUserCert(nss_cert.get()));
   if (import_status != net::OK) {
     LOG(ERROR) << "Could not import certificate.";
     state->OnError(FROM_HERE, net::ErrorToString(import_status));
@@ -683,13 +702,19 @@
 void RemoveCertificateWithDB(std::unique_ptr<RemoveCertificateState> state,
                              net::NSSCertDatabase* cert_db) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  // Get the pointer before base::Passed clears |state|.
-  scoped_refptr<net::X509Certificate> certificate = state->certificate_;
-  bool certificate_found = certificate->os_cert_handle()->isperm;
+
+  net::ScopedCERTCertificate nss_cert =
+      net::x509_util::CreateCERTCertificateFromX509Certificate(
+          state->certificate_.get());
+  if (!nss_cert) {
+    state->OnError(FROM_HERE, net::ErrorToString(net::ERR_CERT_INVALID));
+    return;
+  }
+
+  bool certificate_found = nss_cert->isperm;
   cert_db->DeleteCertAndKeyAsync(
-      certificate,
-      base::Bind(
-          &DidRemoveCertificate, base::Passed(&state), certificate_found));
+      std::move(nss_cert), base::Bind(&DidRemoveCertificate,
+                                      base::Passed(&state), certificate_found));
 }
 
 // Does the actual work to determine which tokens are available.
@@ -807,8 +832,15 @@
 
 std::string GetSubjectPublicKeyInfo(
     const scoped_refptr<net::X509Certificate>& certificate) {
-  const SECItem& spki_der = certificate->os_cert_handle()->derPublicKey;
-  return std::string(spki_der.data, spki_der.data + spki_der.len);
+  std::string der_bytes;
+  if (!net::X509Certificate::GetDEREncoded(certificate->os_cert_handle(),
+                                           &der_bytes))
+    return {};
+
+  base::StringPiece spki_bytes;
+  if (!net::asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes))
+    return {};
+  return spki_bytes.as_string();
 }
 
 bool GetPublicKey(const scoped_refptr<net::X509Certificate>& certificate,
@@ -829,14 +861,24 @@
     return false;
   }
 
-  crypto::ScopedSECKEYPublicKey public_key(
-      CERT_ExtractPublicKey(certificate->os_cert_handle()));
-  if (!public_key) {
+  std::string spki = GetSubjectPublicKeyInfo(certificate);
+  crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+  CBS cbs;
+  CBS_init(&cbs, reinterpret_cast<const uint8_t*>(spki.data()), spki.size());
+  bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_public_key(&cbs));
+  if (!pkey) {
     LOG(WARNING) << "Could not extract public key of certificate.";
     return false;
   }
-  long public_exponent = DER_GetInteger(&public_key->u.rsa.publicExponent);
-  if (public_exponent != 65537L) {
+  RSA* rsa = EVP_PKEY_get0_RSA(pkey.get());
+  if (!rsa) {
+    LOG(WARNING) << "Could not get RSA from PKEY.";
+    return false;
+  }
+
+  const BIGNUM* public_exponent;
+  RSA_get0_key(rsa, nullptr /* out_n */, &public_exponent, nullptr /* out_d */);
+  if (BN_get_word(public_exponent) != 65537L) {
     LOG(ERROR) << "Rejecting RSA public exponent that is unequal 65537.";
     return false;
   }
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
index e499306..b62c6f5f 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
@@ -494,14 +494,12 @@
   }
 
   bool SetupCertificates() {
-    scoped_refptr<net::X509Certificate> system_ca_cert =
-        net::ImportCertFromFile(net::GetTestCertsDirectory(),
-                                "client_1_ca.pem");
-    if (!system_ca_cert)
+    net::ScopedCERTCertificateList cert_list =
+        net::CreateCERTCertificateListFromFile(
+            net::GetTestCertsDirectory(), "client_1_ca.pem",
+            net::X509Certificate::FORMAT_AUTO);
+    if (cert_list.empty())
       return false;
-
-    net::CertificateList cert_list;
-    cert_list.push_back(std::move(system_ca_cert));
     // TODO(stevenjb): Figure out a simple way to import a test user cert.
 
     chromeos::NetworkHandler::Get()