LCOV - code coverage report
Current view: top level - security/apps - AppTrustDomain.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 3 130 2.3 %
Date: 2017-07-14 16:53:18 Functions: 2 17 11.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "AppTrustDomain.h"
       8             : 
       9             : #include "MainThreadUtils.h"
      10             : #include "certdb.h"
      11             : #include "mozilla/ArrayUtils.h"
      12             : #include "mozilla/Casting.h"
      13             : #include "mozilla/Preferences.h"
      14             : #include "nsComponentManagerUtils.h"
      15             : #include "nsIFile.h"
      16             : #include "nsIFileStreams.h"
      17             : #include "nsIX509CertDB.h"
      18             : #include "nsNSSCertificate.h"
      19             : #include "nsNetUtil.h"
      20             : #include "pkix/pkixnss.h"
      21             : #include "prerror.h"
      22             : 
      23             : // Generated by gen_cert_header.py, which gets called by the build system.
      24             : #include "xpcshell.inc"
      25             : // Add-on signing Certificates
      26             : #include "addons-public.inc"
      27             : #include "addons-stage.inc"
      28             : // Privileged Package Certificates
      29             : #include "privileged-package-root.inc"
      30             : 
      31             : using namespace mozilla::pkix;
      32             : 
      33             : extern mozilla::LazyLogModule gPIPNSSLog;
      34             : 
      35             : static char kDevImportedDER[] =
      36             :   "network.http.signed-packages.developer-root";
      37             : 
      38             : namespace mozilla { namespace psm {
      39             : 
      40           3 : StaticMutex AppTrustDomain::sMutex;
      41           3 : UniquePtr<unsigned char[]> AppTrustDomain::sDevImportedDERData;
      42             : unsigned int AppTrustDomain::sDevImportedDERLen = 0;
      43             : 
      44           0 : AppTrustDomain::AppTrustDomain(UniqueCERTCertList& certChain, void* pinArg)
      45             :   : mCertChain(certChain)
      46           0 :   , mPinArg(pinArg)
      47             : {
      48           0 : }
      49             : 
      50             : nsresult
      51           0 : AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
      52             : {
      53             :   SECItem trustedDER;
      54             : 
      55             :   // Load the trusted certificate into the in-memory NSS database so that
      56             :   // CERT_CreateSubjectCertList can find it.
      57             : 
      58           0 :   switch (trustedRoot)
      59             :   {
      60             :     case nsIX509CertDB::AppXPCShellRoot:
      61           0 :       trustedDER.data = const_cast<uint8_t*>(xpcshellRoot);
      62           0 :       trustedDER.len = mozilla::ArrayLength(xpcshellRoot);
      63           0 :       break;
      64             : 
      65             :     case nsIX509CertDB::AddonsPublicRoot:
      66           0 :       trustedDER.data = const_cast<uint8_t*>(addonsPublicRoot);
      67           0 :       trustedDER.len = mozilla::ArrayLength(addonsPublicRoot);
      68           0 :       break;
      69             : 
      70             :     case nsIX509CertDB::AddonsStageRoot:
      71           0 :       trustedDER.data = const_cast<uint8_t*>(addonsStageRoot);
      72           0 :       trustedDER.len = mozilla::ArrayLength(addonsStageRoot);
      73           0 :       break;
      74             : 
      75             :     case nsIX509CertDB::PrivilegedPackageRoot:
      76           0 :       trustedDER.data = const_cast<uint8_t*>(privilegedPackageRoot);
      77           0 :       trustedDER.len = mozilla::ArrayLength(privilegedPackageRoot);
      78           0 :       break;
      79             : 
      80             :     case nsIX509CertDB::DeveloperImportedRoot: {
      81           0 :       StaticMutexAutoLock lock(sMutex);
      82           0 :       if (!sDevImportedDERData) {
      83           0 :         MOZ_ASSERT(!NS_IsMainThread());
      84           0 :         nsCOMPtr<nsIFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
      85           0 :         if (!file) {
      86           0 :           return NS_ERROR_FAILURE;
      87             :         }
      88           0 :         nsresult rv = file->InitWithNativePath(
      89           0 :           Preferences::GetCString(kDevImportedDER));
      90           0 :         if (NS_FAILED(rv)) {
      91           0 :           return rv;
      92             :         }
      93             : 
      94           0 :         nsCOMPtr<nsIInputStream> inputStream;
      95           0 :         rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file, -1,
      96           0 :                                         -1, nsIFileInputStream::CLOSE_ON_EOF);
      97           0 :         if (NS_FAILED(rv)) {
      98           0 :           return rv;
      99             :         }
     100             : 
     101             :         uint64_t length;
     102           0 :         rv = inputStream->Available(&length);
     103           0 :         if (NS_FAILED(rv)) {
     104           0 :           return rv;
     105             :         }
     106             : 
     107           0 :         auto data = MakeUnique<char[]>(length);
     108           0 :         rv = inputStream->Read(data.get(), length, &sDevImportedDERLen);
     109           0 :         if (NS_FAILED(rv)) {
     110           0 :           return rv;
     111             :         }
     112             : 
     113           0 :         MOZ_ASSERT(length == sDevImportedDERLen);
     114           0 :         sDevImportedDERData.reset(
     115           0 :           BitwiseCast<unsigned char*, char*>(data.release()));
     116             :       }
     117             : 
     118           0 :       trustedDER.data = sDevImportedDERData.get();
     119           0 :       trustedDER.len = sDevImportedDERLen;
     120           0 :       break;
     121             :     }
     122             : 
     123             :     default:
     124           0 :       return NS_ERROR_INVALID_ARG;
     125             :   }
     126             : 
     127           0 :   mTrustedRoot.reset(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
     128           0 :                                              &trustedDER, nullptr, false, true));
     129           0 :   if (!mTrustedRoot) {
     130           0 :     return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
     131             :   }
     132             : 
     133           0 :   return NS_OK;
     134             : }
     135             : 
     136             : Result
     137           0 : AppTrustDomain::FindIssuer(Input encodedIssuerName, IssuerChecker& checker,
     138             :                            Time)
     139             : 
     140             : {
     141           0 :   MOZ_ASSERT(mTrustedRoot);
     142           0 :   if (!mTrustedRoot) {
     143           0 :     return Result::FATAL_ERROR_INVALID_STATE;
     144             :   }
     145             : 
     146             :   // TODO(bug 1035418): If/when mozilla::pkix relaxes the restriction that
     147             :   // FindIssuer must only pass certificates with a matching subject name to
     148             :   // checker.Check, we can stop using CERT_CreateSubjectCertList and instead
     149             :   // use logic like this:
     150             :   //
     151             :   // 1. First, try the trusted trust anchor.
     152             :   // 2. Secondly, iterate through the certificates that were stored in the CMS
     153             :   //    message, passing each one to checker.Check.
     154             :   SECItem encodedIssuerNameSECItem =
     155           0 :     UnsafeMapInputToSECItem(encodedIssuerName);
     156             :   UniqueCERTCertList
     157             :     candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
     158             :                                           &encodedIssuerNameSECItem, 0,
     159           0 :                                           false));
     160           0 :   if (candidates) {
     161           0 :     for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
     162           0 :          !CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
     163           0 :       Input certDER;
     164           0 :       Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
     165           0 :       if (rv != Success) {
     166           0 :         continue; // probably too big
     167             :       }
     168             : 
     169             :       bool keepGoing;
     170             :       rv = checker.Check(certDER, nullptr/*additionalNameConstraints*/,
     171           0 :                          keepGoing);
     172           0 :       if (rv != Success) {
     173           0 :         return rv;
     174             :       }
     175           0 :       if (!keepGoing) {
     176           0 :         break;
     177             :       }
     178             :     }
     179             :   }
     180             : 
     181           0 :   return Success;
     182             : }
     183             : 
     184             : Result
     185           0 : AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
     186             :                              const CertPolicyId& policy,
     187             :                              Input candidateCertDER,
     188             :                      /*out*/ TrustLevel& trustLevel)
     189             : {
     190           0 :   MOZ_ASSERT(policy.IsAnyPolicy());
     191           0 :   MOZ_ASSERT(mTrustedRoot);
     192           0 :   if (!policy.IsAnyPolicy()) {
     193           0 :     return Result::FATAL_ERROR_INVALID_ARGS;
     194             :   }
     195           0 :   if (!mTrustedRoot) {
     196           0 :     return Result::FATAL_ERROR_INVALID_STATE;
     197             :   }
     198             : 
     199             :   // Handle active distrust of the certificate.
     200             : 
     201             :   // XXX: This would be cleaner and more efficient if we could get the trust
     202             :   // information without constructing a CERTCertificate here, but NSS doesn't
     203             :   // expose it in any other easy-to-use fashion.
     204             :   SECItem candidateCertDERSECItem =
     205           0 :     UnsafeMapInputToSECItem(candidateCertDER);
     206             :   UniqueCERTCertificate candidateCert(
     207             :     CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &candidateCertDERSECItem,
     208           0 :                             nullptr, false, true));
     209           0 :   if (!candidateCert) {
     210           0 :     return MapPRErrorCodeToResult(PR_GetError());
     211             :   }
     212             : 
     213             :   CERTCertTrust trust;
     214           0 :   if (CERT_GetCertTrust(candidateCert.get(), &trust) == SECSuccess) {
     215           0 :     uint32_t flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning);
     216             : 
     217             :     // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit,
     218             :     // because we can have active distrust for either type of cert. Note that
     219             :     // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the
     220             :     // relevant trust bit isn't set then that means the cert must be considered
     221             :     // distrusted.
     222             :     uint32_t relevantTrustBit = endEntityOrCA == EndEntityOrCA::MustBeCA
     223           0 :                               ? CERTDB_TRUSTED_CA
     224           0 :                               : CERTDB_TRUSTED;
     225           0 :     if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD)))
     226             :             == CERTDB_TERMINAL_RECORD) {
     227           0 :       trustLevel = TrustLevel::ActivelyDistrusted;
     228           0 :       return Success;
     229             :     }
     230             :   }
     231             : 
     232             :   // mTrustedRoot is the only trust anchor for this validation.
     233           0 :   if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert.get())) {
     234           0 :     trustLevel = TrustLevel::TrustAnchor;
     235           0 :     return Success;
     236             :   }
     237             : 
     238           0 :   trustLevel = TrustLevel::InheritsTrust;
     239           0 :   return Success;
     240             : }
     241             : 
     242             : Result
     243           0 : AppTrustDomain::DigestBuf(Input item,
     244             :                           DigestAlgorithm digestAlg,
     245             :                           /*out*/ uint8_t* digestBuf,
     246             :                           size_t digestBufLen)
     247             : {
     248           0 :   return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
     249             : }
     250             : 
     251             : Result
     252           0 : AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
     253             :                                 /*optional*/ const Input*,
     254             :                                 /*optional*/ const Input*)
     255             : {
     256             :   // We don't currently do revocation checking. If we need to distrust an Apps
     257             :   // certificate, we will use the active distrust mechanism.
     258           0 :   return Success;
     259             : }
     260             : 
     261             : Result
     262           0 : AppTrustDomain::IsChainValid(const DERArray& certChain, Time time,
     263             :                              const CertPolicyId& requiredPolicy)
     264             : {
     265           0 :   MOZ_ASSERT(requiredPolicy.IsAnyPolicy());
     266           0 :   SECStatus srv = ConstructCERTCertListFromReversedDERArray(certChain,
     267           0 :                                                             mCertChain);
     268           0 :   if (srv != SECSuccess) {
     269           0 :     return MapPRErrorCodeToResult(PR_GetError());
     270             :   }
     271           0 :   return Success;
     272             : }
     273             : 
     274             : Result
     275           0 : AppTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm,
     276             :                                               EndEntityOrCA,
     277             :                                               Time)
     278             : {
     279             :   // TODO: We should restrict signatures to SHA-256 or better.
     280           0 :   return Success;
     281             : }
     282             : 
     283             : Result
     284           0 : AppTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
     285             :   EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits)
     286             : {
     287           0 :   if (modulusSizeInBits < 2048u) {
     288           0 :     return Result::ERROR_INADEQUATE_KEY_SIZE;
     289             :   }
     290           0 :   return Success;
     291             : }
     292             : 
     293             : Result
     294           0 : AppTrustDomain::VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
     295             :                                            Input subjectPublicKeyInfo)
     296             : {
     297             :   // TODO: We should restrict signatures to SHA-256 or better.
     298           0 :   return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
     299           0 :                                        mPinArg);
     300             : }
     301             : 
     302             : Result
     303           0 : AppTrustDomain::CheckECDSACurveIsAcceptable(EndEntityOrCA /*endEntityOrCA*/,
     304             :                                             NamedCurve curve)
     305             : {
     306           0 :   switch (curve) {
     307             :     case NamedCurve::secp256r1: // fall through
     308             :     case NamedCurve::secp384r1: // fall through
     309             :     case NamedCurve::secp521r1:
     310           0 :       return Success;
     311             :   }
     312             : 
     313           0 :   return Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
     314             : }
     315             : 
     316             : Result
     317           0 : AppTrustDomain::VerifyECDSASignedDigest(const SignedDigest& signedDigest,
     318             :                                         Input subjectPublicKeyInfo)
     319             : {
     320           0 :   return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo,
     321           0 :                                     mPinArg);
     322             : }
     323             : 
     324             : Result
     325           0 : AppTrustDomain::CheckValidityIsAcceptable(Time /*notBefore*/, Time /*notAfter*/,
     326             :                                           EndEntityOrCA /*endEntityOrCA*/,
     327             :                                           KeyPurposeId /*keyPurpose*/)
     328             : {
     329           0 :   return Success;
     330             : }
     331             : 
     332             : Result
     333           0 : AppTrustDomain::NetscapeStepUpMatchesServerAuth(Time /*notBefore*/,
     334             :                                                 /*out*/ bool& matches)
     335             : {
     336           0 :   matches = false;
     337           0 :   return Success;
     338             : }
     339             : 
     340             : void
     341           0 : AppTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension /*extension*/,
     342             :                                        Input /*extensionData*/)
     343             : {
     344           0 : }
     345             : 
     346           9 : } } // namespace mozilla::psm

Generated by: LCOV version 1.13