michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef MOZ_LOGGING michael@0: #define FORCE_PR_LOG 1 michael@0: #endif michael@0: michael@0: #include "AppTrustDomain.h" michael@0: #include "certdb.h" michael@0: #include "pkix/pkix.h" michael@0: #include "mozilla/ArrayUtils.h" michael@0: #include "nsIX509CertDB.h" michael@0: #include "prerror.h" michael@0: #include "secerr.h" michael@0: michael@0: // Generated in Makefile.in michael@0: #include "marketplace-prod-public.inc" michael@0: #include "marketplace-prod-reviewers.inc" michael@0: #include "marketplace-dev-public.inc" michael@0: #include "marketplace-dev-reviewers.inc" michael@0: #include "xpcshell.inc" michael@0: michael@0: using namespace mozilla::pkix; michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gPIPNSSLog; michael@0: #endif michael@0: michael@0: namespace mozilla { namespace psm { michael@0: michael@0: AppTrustDomain::AppTrustDomain(void* pinArg) michael@0: : mPinArg(pinArg) michael@0: { michael@0: } michael@0: michael@0: SECStatus michael@0: AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot) michael@0: { michael@0: SECItem trustedDER; michael@0: michael@0: // Load the trusted certificate into the in-memory NSS database so that michael@0: // CERT_CreateSubjectCertList can find it. michael@0: michael@0: switch (trustedRoot) michael@0: { michael@0: case nsIX509CertDB::AppMarketplaceProdPublicRoot: michael@0: trustedDER.data = const_cast(marketplaceProdPublicRoot); michael@0: trustedDER.len = mozilla::ArrayLength(marketplaceProdPublicRoot); michael@0: break; michael@0: michael@0: case nsIX509CertDB::AppMarketplaceProdReviewersRoot: michael@0: trustedDER.data = const_cast(marketplaceProdReviewersRoot); michael@0: trustedDER.len = mozilla::ArrayLength(marketplaceProdReviewersRoot); michael@0: break; michael@0: michael@0: case nsIX509CertDB::AppMarketplaceDevPublicRoot: michael@0: trustedDER.data = const_cast(marketplaceDevPublicRoot); michael@0: trustedDER.len = mozilla::ArrayLength(marketplaceDevPublicRoot); michael@0: break; michael@0: michael@0: case nsIX509CertDB::AppMarketplaceDevReviewersRoot: michael@0: trustedDER.data = const_cast(marketplaceDevReviewersRoot); michael@0: trustedDER.len = mozilla::ArrayLength(marketplaceDevReviewersRoot); michael@0: break; michael@0: michael@0: case nsIX509CertDB::AppXPCShellRoot: michael@0: trustedDER.data = const_cast(xpcshellRoot); michael@0: trustedDER.len = mozilla::ArrayLength(xpcshellRoot); michael@0: break; michael@0: michael@0: default: michael@0: PR_SetError(SEC_ERROR_INVALID_ARGS, 0); michael@0: return SECFailure; michael@0: } michael@0: michael@0: mTrustedRoot = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), michael@0: &trustedDER, nullptr, false, true); michael@0: if (!mTrustedRoot) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: AppTrustDomain::FindPotentialIssuers(const SECItem* encodedIssuerName, michael@0: PRTime time, michael@0: /*out*/ mozilla::pkix::ScopedCERTCertList& results) michael@0: { michael@0: MOZ_ASSERT(mTrustedRoot); michael@0: if (!mTrustedRoot) { michael@0: PR_SetError(PR_INVALID_STATE_ERROR, 0); michael@0: return SECFailure; michael@0: } michael@0: michael@0: results = CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(), michael@0: encodedIssuerName, time, true); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA, michael@0: SECOidTag policy, michael@0: const CERTCertificate* candidateCert, michael@0: /*out*/ TrustLevel* trustLevel) michael@0: { michael@0: MOZ_ASSERT(policy == SEC_OID_X509_ANY_POLICY); michael@0: MOZ_ASSERT(candidateCert); michael@0: MOZ_ASSERT(trustLevel); michael@0: MOZ_ASSERT(mTrustedRoot); michael@0: if (!candidateCert || !trustLevel || policy != SEC_OID_X509_ANY_POLICY) { michael@0: PR_SetError(SEC_ERROR_INVALID_ARGS, 0); michael@0: return SECFailure; michael@0: } michael@0: if (!mTrustedRoot) { michael@0: PR_SetError(PR_INVALID_STATE_ERROR, 0); michael@0: return SECFailure; michael@0: } michael@0: michael@0: // Handle active distrust of the certificate. michael@0: CERTCertTrust trust; michael@0: if (CERT_GetCertTrust(candidateCert, &trust) == SECSuccess) { michael@0: PRUint32 flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning); michael@0: michael@0: // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit, michael@0: // because we can have active distrust for either type of cert. Note that michael@0: // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the michael@0: // relevant trust bit isn't set then that means the cert must be considered michael@0: // distrusted. michael@0: PRUint32 relevantTrustBit = endEntityOrCA == MustBeCA michael@0: ? CERTDB_TRUSTED_CA michael@0: : CERTDB_TRUSTED; michael@0: if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD))) michael@0: == CERTDB_TERMINAL_RECORD) { michael@0: *trustLevel = ActivelyDistrusted; michael@0: return SECSuccess; michael@0: } michael@0: michael@0: #ifdef MOZ_B2G_CERTDATA michael@0: // XXX(Bug 972201): We have to allow the old way of supporting additional michael@0: // roots until we fix bug 889744. Remove this along with the rest of the michael@0: // MOZ_B2G_CERTDATA stuff. michael@0: michael@0: // For TRUST, we only use the CERTDB_TRUSTED_CA bit, because Gecko hasn't michael@0: // needed to consider end-entity certs to be their own trust anchors since michael@0: // Gecko implemented nsICertOverrideService. michael@0: if (flags & CERTDB_TRUSTED_CA) { michael@0: *trustLevel = TrustAnchor; michael@0: return SECSuccess; michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: // mTrustedRoot is the only trust anchor for this validation. michael@0: if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert)) { michael@0: *trustLevel = TrustAnchor; michael@0: return SECSuccess; michael@0: } michael@0: michael@0: *trustLevel = InheritsTrust; michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: AppTrustDomain::VerifySignedData(const CERTSignedData* signedData, michael@0: const CERTCertificate* cert) michael@0: { michael@0: return ::mozilla::pkix::VerifySignedData(signedData, cert, mPinArg); michael@0: } michael@0: michael@0: SECStatus michael@0: AppTrustDomain::CheckRevocation(EndEntityOrCA, michael@0: const CERTCertificate*, michael@0: /*const*/ CERTCertificate*, michael@0: PRTime time, michael@0: /*optional*/ const SECItem*) michael@0: { michael@0: // We don't currently do revocation checking. If we need to distrust an Apps michael@0: // certificate, we will use the active distrust mechanism. michael@0: return SECSuccess; michael@0: } michael@0: michael@0: } }