summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/CSTrustDomain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'security/manager/ssl/CSTrustDomain.cpp')
-rw-r--r--security/manager/ssl/CSTrustDomain.cpp231
1 files changed, 231 insertions, 0 deletions
diff --git a/security/manager/ssl/CSTrustDomain.cpp b/security/manager/ssl/CSTrustDomain.cpp
new file mode 100644
index 000000000..90008038e
--- /dev/null
+++ b/security/manager/ssl/CSTrustDomain.cpp
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "CSTrustDomain.h"
+#include "mozilla/Base64.h"
+#include "mozilla/Preferences.h"
+#include "nsNSSCertificate.h"
+#include "nsNSSComponent.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+#include "pkix/pkixnss.h"
+
+using namespace mozilla::pkix;
+
+namespace mozilla { namespace psm {
+
+static LazyLogModule gTrustDomainPRLog("CSTrustDomain");
+#define CSTrust_LOG(args) MOZ_LOG(gTrustDomainPRLog, LogLevel::Debug, args)
+
+CSTrustDomain::CSTrustDomain(UniqueCERTCertList& certChain)
+ : mCertChain(certChain)
+ , mCertBlocklist(do_GetService(NS_CERTBLOCKLIST_CONTRACTID))
+{
+}
+
+Result
+CSTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
+ const CertPolicyId& policy, Input candidateCertDER,
+ /*out*/ TrustLevel& trustLevel)
+{
+ MOZ_ASSERT(policy.IsAnyPolicy());
+ if (!policy.IsAnyPolicy()) {
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+
+ SECItem candidateCertDERSECItem = UnsafeMapInputToSECItem(candidateCertDER);
+ UniqueCERTCertificate candidateCert(
+ CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &candidateCertDERSECItem,
+ nullptr, false, true));
+ if (!candidateCert) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+
+ bool isCertRevoked;
+ nsresult nsrv = mCertBlocklist->IsCertRevoked(
+ candidateCert->derIssuer.data,
+ candidateCert->derIssuer.len,
+ candidateCert->serialNumber.data,
+ candidateCert->serialNumber.len,
+ candidateCert->derSubject.data,
+ candidateCert->derSubject.len,
+ candidateCert->derPublicKey.data,
+ candidateCert->derPublicKey.len,
+ &isCertRevoked);
+ if (NS_FAILED(nsrv)) {
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
+ }
+
+ if (isCertRevoked) {
+ CSTrust_LOG(("CSTrustDomain: certificate is revoked\n"));
+ return Result::ERROR_REVOKED_CERTIFICATE;
+ }
+
+ // Is this cert our built-in content signing root?
+ bool isRoot = false;
+ nsCOMPtr<nsINSSComponent> component(do_GetService(PSM_COMPONENT_CONTRACTID));
+ if (!component) {
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
+ }
+ nsrv = component->IsCertContentSigningRoot(candidateCert.get(), isRoot);
+ if (NS_FAILED(nsrv)) {
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
+ }
+ if (isRoot) {
+ CSTrust_LOG(("CSTrustDomain: certificate is a trust anchor\n"));
+ trustLevel = TrustLevel::TrustAnchor;
+ return Success;
+ }
+ CSTrust_LOG(("CSTrustDomain: certificate is *not* a trust anchor\n"));
+
+ trustLevel = TrustLevel::InheritsTrust;
+ return Success;
+}
+
+Result
+CSTrustDomain::FindIssuer(Input encodedIssuerName, IssuerChecker& checker,
+ Time time)
+{
+ // Loop over the chain, look for a matching subject
+ for (CERTCertListNode* n = CERT_LIST_HEAD(mCertChain);
+ !CERT_LIST_END(n, mCertChain); n = CERT_LIST_NEXT(n)) {
+ Input certDER;
+ Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
+ if (rv != Success) {
+ continue; // probably too big
+ }
+
+ // if the subject does not match, try the next certificate
+ Input subjectDER;
+ rv = subjectDER.Init(n->cert->derSubject.data, n->cert->derSubject.len);
+ if (rv != Success) {
+ continue; // just try the next one
+ }
+ if (!InputsAreEqual(subjectDER, encodedIssuerName)) {
+ CSTrust_LOG(("CSTrustDomain: subjects don't match\n"));
+ continue;
+ }
+
+ // If the subject does match, try the next step
+ bool keepGoing;
+ rv = checker.Check(certDER, nullptr/*additionalNameConstraints*/,
+ keepGoing);
+ if (rv != Success) {
+ return rv;
+ }
+ if (!keepGoing) {
+ CSTrust_LOG(("CSTrustDomain: don't keep going\n"));
+ break;
+ }
+ }
+
+ return Success;
+}
+
+Result
+CSTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
+ const CertID& certID, Time time,
+ Duration validityDuration,
+ /*optional*/ const Input* stapledOCSPresponse,
+ /*optional*/ const Input* aiaExtension)
+{
+ // We're relying solely on the CertBlocklist for revocation - and we're
+ // performing checks on this in GetCertTrust (as per nsNSSCertDBTrustDomain)
+ return Success;
+}
+
+Result
+CSTrustDomain::IsChainValid(const DERArray& certChain, Time time)
+{
+ // Check that our chain is not empty
+ if (certChain.GetLength() == 0) {
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
+ }
+
+ return Success;
+}
+
+Result
+CSTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg,
+ EndEntityOrCA endEntityOrCA,
+ Time notBefore)
+{
+ if (digestAlg == DigestAlgorithm::sha1) {
+ return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
+ }
+ return Success;
+}
+
+Result
+CSTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
+ EndEntityOrCA endEntityOrCA, unsigned int modulusSizeInBits)
+{
+ if (modulusSizeInBits < 2048) {
+ return Result::ERROR_INADEQUATE_KEY_SIZE;
+ }
+ return Success;
+}
+
+Result
+CSTrustDomain::VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
+ Input subjectPublicKeyInfo)
+{
+ return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
+ nullptr);
+}
+
+Result
+CSTrustDomain::CheckECDSACurveIsAcceptable(EndEntityOrCA endEntityOrCA,
+ NamedCurve curve)
+{
+ switch (curve) {
+ case NamedCurve::secp256r1: // fall through
+ case NamedCurve::secp384r1: // fall through
+ case NamedCurve::secp521r1:
+ return Success;
+ }
+
+ return Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
+}
+
+Result
+CSTrustDomain::VerifyECDSASignedDigest(const SignedDigest& signedDigest,
+ Input subjectPublicKeyInfo)
+{
+ return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo,
+ nullptr);
+}
+
+Result
+CSTrustDomain::CheckValidityIsAcceptable(Time notBefore, Time notAfter,
+ EndEntityOrCA endEntityOrCA,
+ KeyPurposeId keyPurpose)
+{
+ return Success;
+}
+
+Result
+CSTrustDomain::NetscapeStepUpMatchesServerAuth(Time notBefore,
+ /*out*/ bool& matches)
+{
+ matches = false;
+ return Success;
+}
+
+void
+CSTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension /*extension*/,
+ Input /*extensionData*/)
+{
+}
+
+Result
+CSTrustDomain::DigestBuf(Input item, DigestAlgorithm digestAlg,
+ /*out*/ uint8_t* digestBuf, size_t digestBufLen)
+{
+ return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
+}
+
+} } // end namespace mozilla::psm