summaryrefslogtreecommitdiffstats
path: root/security/certverifier/TrustOverrideUtils.h
diff options
context:
space:
mode:
Diffstat (limited to 'security/certverifier/TrustOverrideUtils.h')
-rw-r--r--security/certverifier/TrustOverrideUtils.h149
1 files changed, 149 insertions, 0 deletions
diff --git a/security/certverifier/TrustOverrideUtils.h b/security/certverifier/TrustOverrideUtils.h
new file mode 100644
index 0000000000..5c92cad45b
--- /dev/null
+++ b/security/certverifier/TrustOverrideUtils.h
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+#ifndef TrustOverrides_h
+#define TrustOverrides_h
+
+#include "mozilla/ArrayUtils.h"
+#include "mozpkix/pkix.h"
+#include "mozpkix/pkixnss.h"
+#include "mozpkix/pkixutil.h"
+
+using namespace mozilla;
+using namespace mozilla::pkix;
+
+struct DataAndLength {
+ const uint8_t* data;
+ uint32_t len;
+};
+
+template <size_t T>
+static bool CertDNIsInList(const nsTArray<uint8_t>& aCert,
+ const DataAndLength (&aDnList)[T]) {
+ Input certInput;
+ mozilla::pkix::Result rv = certInput.Init(aCert.Elements(), aCert.Length());
+ if (rv != Success) {
+ return false;
+ }
+
+ // we don't use the certificate for path building, so this parameter doesn't
+ // matter
+ EndEntityOrCA notUsedForPaths = EndEntityOrCA::MustBeEndEntity;
+ BackCert cert(certInput, notUsedForPaths, nullptr);
+ rv = cert.Init();
+ if (rv != Success) {
+ return false;
+ }
+
+ Input subject(cert.GetSubject());
+
+ for (auto& dn : aDnList) {
+ Input dnInput;
+ rv = dnInput.Init(dn.data, dn.len);
+ if (rv != Success) {
+ return false;
+ }
+
+ if (InputsAreEqual(subject, dnInput)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template <size_t T>
+static bool CertSPKIIsInList(Input aCertInput,
+ const DataAndLength (&aSpkiList)[T]) {
+ // we don't use the certificate for path building, so this parameter doesn't
+ // matter
+ EndEntityOrCA notUsedForPaths = EndEntityOrCA::MustBeEndEntity;
+ BackCert cert(aCertInput, notUsedForPaths, nullptr);
+ mozilla::pkix::Result rv = cert.Init();
+ if (rv != Success) {
+ return false;
+ }
+
+ Input publicKey(cert.GetSubjectPublicKeyInfo());
+
+ for (auto& spki : aSpkiList) {
+ Input spkiInput;
+ rv = spkiInput.Init(spki.data, spki.len);
+ if (rv != Success) {
+ return false;
+ }
+
+ if (InputsAreEqual(publicKey, spkiInput)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template <size_t T, size_t R>
+static bool CertMatchesStaticData(const nsTArray<uint8_t>& aCert,
+ const unsigned char (&subject)[T],
+ const unsigned char (&spki)[R]) {
+ Input certInput;
+ mozilla::pkix::Result rv = certInput.Init(aCert.Elements(), aCert.Length());
+ if (rv != Success) {
+ return false;
+ }
+
+ // we don't use the certificate for path building, so this parameter doesn't
+ // matter
+ EndEntityOrCA notUsedForPaths = EndEntityOrCA::MustBeEndEntity;
+ BackCert cert(certInput, notUsedForPaths, nullptr);
+ rv = cert.Init();
+ if (rv != Success) {
+ return false;
+ }
+
+ Input certSubject(cert.GetSubject());
+ Input certSPKI(cert.GetSubjectPublicKeyInfo());
+
+ Input subjectInput;
+ rv = subjectInput.Init(subject, T);
+ if (rv != Success) {
+ return false;
+ }
+
+ Input spkiInput;
+ rv = spkiInput.Init(spki, R);
+ if (rv != Success) {
+ return false;
+ }
+
+ return InputsAreEqual(certSubject, subjectInput) &&
+ InputsAreEqual(certSPKI, spkiInput);
+}
+
+// Implements the graduated Symantec distrust algorithm from Bug 1409257.
+// This accepts a pre-segmented certificate chain (e.g. SegmentCertificateChain)
+// as |intCerts|, and pre-assumes that the root has been identified
+// as being affected (this is to avoid duplicate Segment operations in the
+// NSSCertDBTrustDomain). Each of the |intCerts| is evaluated against a
+// |allowlist| of SPKI entries, and if a match is found, then this returns
+// "not distrusted." Otherwise, due to the precondition holding, the chain is
+// "distrusted."
+template <size_t T>
+static nsresult CheckForSymantecDistrust(const nsTArray<Input>& intCerts,
+ const DataAndLength (&allowlist)[T],
+ /* out */ bool& isDistrusted) {
+ // PRECONDITION: The rootCert is already verified as being one of the
+ // affected Symantec roots
+
+ isDistrusted = true;
+
+ for (const auto& cert : intCerts) {
+ if (CertSPKIIsInList(cert, allowlist)) {
+ isDistrusted = false;
+ break;
+ }
+ }
+ return NS_OK;
+}
+
+#endif // TrustOverrides_h