certificatessl-certificatenssroot-certificate

How do I use the Mozilla NSS Root Certificate store on Windows, Mac, and Linux?


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?


Solution

  • 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;
    }