0

NSS comes with very little documentation, and a heavily vestigial API. How does it work? It is used for firefox on Window and Mac, and Chrome as well on linux. How do I install, uninstall, and check installation of my own Root Cert?

4

1 回答 1

1

See this gist, here: https://gist.github.com/pehrlich/08852e8f7da81e136d70

The meat of it is CertificateNSS.cpp, copied here:

#include "stdafx.h"
#include "CertificateNSS.h"
#include "Certificate.h"
#include <boost/filesystem/operations.hpp>

#include <nss.h>
#include <cert.h>
#include <certdb.h>

ProfileLocker::ProfileLocker(const boost::filesystem::path& profilePath) : m_isValid(false)
{
  GetSharedMutex().lock();
  m_isValid = (NSS_InitReadWrite(profilePath.string().c_str()) == SECSuccess);
  if (!m_isValid) {
    GetSharedMutex().unlock();
  }
}

ProfileLocker::~ProfileLocker()
{
  if (m_isValid) {
    NSS_Shutdown();
    GetSharedMutex().unlock();
  }
}

std::mutex& ProfileLocker::GetSharedMutex()
{
  static std::mutex s_mutex;
  return s_mutex;
}

std::vector<boost::filesystem::path> CertificateNSS::GetUserProfiles()
{
  std::vector<boost::filesystem::path> profiles;

  const auto path = GetProfilesDirectory();
  if (!boost::filesystem::is_directory(path)) {
    return profiles;
  }
  boost::filesystem::directory_iterator endIt;
  for (boost::filesystem::directory_iterator it(path); it != endIt; ++it) {
    if (boost::filesystem::is_directory(it->status())) {
      profiles.push_back(it->path());
    }
  }
  return profiles;
}

bool CertificateNSS::Install() const
{
  std::string derCert = m_cert.GetBytes(CertEncoding::DER);
  if (derCert.empty()) {
    return false;
  }
  bool wasInstalled = false;
  CERTCertDBHandle* certdb = CERT_GetDefaultCertDB();
  if (certdb) {
    SECItem cert = { siBuffer, (unsigned char*)derCert.c_str(), static_cast<unsigned int>(derCert.size()) };
    SECItem* certArray[1] = { &cert };
    SECCertUsage noOpUsage = certUsageUserCertImport; // Not used, but required

    CERTCertificate** certificates = nullptr;
    wasInstalled = (CERT_ImportCerts(certdb, noOpUsage, 1, certArray, &certificates, PR_TRUE, PR_TRUE,
      const_cast<char*>(Certificate::GetNickname().c_str())) == SECSuccess);
    if (certificates[0]) {
      CERTCertTrust trust = { CERTDB_TRUSTED_CA | CERTDB_VALID_CA, 0, 0 };
      CERT_ChangeCertTrust(certdb, certificates[0], &trust);
      CERT_DestroyCertificate(certificates[0]);
    }
  }
  return wasInstalled;
}

bool CertificateNSS::IsInstalled() const
{
  std::string derCert = m_cert.GetBytes(CertEncoding::DER);
  if (derCert.empty()) {
    return false;
  }
  bool wasInstalled = false;
  SECItem cert = { siBuffer, (unsigned char*)derCert.c_str(), static_cast<unsigned int>(derCert.size()) };
  CERTCertDBHandle* certdb = CERT_GetDefaultCertDB();
  if (certdb) {
    CERTCertificate* certificate = CERT_FindCertByDERCert(certdb, &cert);
    if (certificate) {
      wasInstalled = true;
      CERT_DestroyCertificate(certificate);
    }
  }
  return wasInstalled;
}

bool CertificateNSS::Uninstall() const
{
  std::string derCert = m_cert.GetBytes(CertEncoding::DER);
  if (derCert.empty()) {
    return false;
  }
  bool wasUninstalled = false;
  SECItem cert = { siBuffer, (unsigned char*)derCert.c_str(), static_cast<unsigned int>(derCert.size()) };
  CERTCertDBHandle* certdb = CERT_GetDefaultCertDB();
  if (certdb) {
    CERTCertificate* certificate = CERT_FindCertByDERCert(certdb, &cert);
    if (certificate) {
      wasUninstalled = (SEC_DeletePermCertificate(certificate) == SECSuccess);
      CERT_DestroyCertificate(certificate);
    }
  }
  return wasUninstalled;
}

bool CertificateNSS::UninstallAll()
{
  bool wasUninstalled = true;
  CERTCertDBHandle* certdb = CERT_GetDefaultCertDB();
  if (!certdb) {
    return true;
  }
  // Delete up to 100 profiles
  for (int i = 0; i < 100; i++) {
    bool failed = true;
    CERTCertificate* certificate = CERT_FindCertByNickname(certdb, Certificate::GetNickname().c_str());
    if (certificate) {
      wasUninstalled = (SEC_DeletePermCertificate(certificate) == SECSuccess);
      if (wasUninstalled) {
        failed = false;
      }
      CERT_DestroyCertificate(certificate);
    }
    if (failed) {
      break;
    }
  }
  return wasUninstalled;
}
于 2015-07-24T19:34:27.537 回答