/* 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/. */
PinningMode GetPinningMode() {
PinningMode pinningMode = static_cast<PinningMode>(
StaticPrefs::security_cert_pinning_enforcement_level_DoNotUseDirectly()); switch (pinningMode) { case PinningMode::Disabled: return PinningMode::Disabled; case PinningMode::AllowUserCAMITM: return PinningMode::AllowUserCAMITM; case PinningMode::Strict: return PinningMode::Strict; case PinningMode::EnforceTestMode: return PinningMode::EnforceTestMode; default: return PinningMode::Disabled;
}
}
/** Computes in the location specified by base64Out the SHA256 digest of the DER Encoded subject Public Key Info for the given cert
*/ static nsresult GetBase64HashSPKI(const BackCert& cert,
nsACString& hashSPKIDigest) {
Input derPublicKey = cert.GetSubjectPublicKeyInfo();
/* * Sets certMatchesPinset to true if a given cert matches any fingerprints from * the given pinset and false otherwise.
*/ static nsresult EvalCert(const BackCert& cert, const StaticFingerprints* fingerprints, /*out*/ bool& certMatchesPinset) {
certMatchesPinset = false; if (!fingerprints) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: No hashes found\n")); return NS_ERROR_INVALID_ARG;
}
if (fingerprints) { for (size_t i = 0; i < fingerprints->size; i++) { if (base64Out.Equals(fingerprints->data[i])) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: found pin base_64 ='%s'\n", base64Out.get()));
certMatchesPinset = true; return NS_OK;
}
}
} return NS_OK;
}
/* * Sets certListIntersectsPinset to true if a given chain matches any * fingerprints from the given static fingerprints and false otherwise.
*/ static nsresult EvalChain(const nsTArray<Span<const uint8_t>>& derCertList, const StaticFingerprints* fingerprints, /*out*/ bool& certListIntersectsPinset) {
certListIntersectsPinset = false; if (!fingerprints) {
MOZ_ASSERT(false, "Must pass in at least one type of pinset"); return NS_ERROR_FAILURE;
}
staticvoid ValidatePinningPreloadList() { if (sValidatedPinningPreloadList) { return;
} for (constauto& entry : kPublicKeyPinningPreloadList) { // If and only if a static entry is a Mozilla entry, it has a telemetry ID.
MOZ_ASSERT((entry.mIsMoz && entry.mId != kUnknownId) ||
(!entry.mIsMoz && entry.mId == kUnknownId));
}
sValidatedPinningPreloadList = true;
} #endif// DEBUG
// Returns via one of the output parameters the most relevant pinning // information that is valid for the given host at the given time. static nsresult FindPinningInformation( constchar* hostname, mozilla::pkix::Time time, /*out*/ const TransportSecurityPreload*& staticFingerprints) { #ifdef DEBUG
ValidatePinningPreloadList(); #endif if (!hostname || hostname[0] == 0) { return NS_ERROR_INVALID_ARG;
}
staticFingerprints = nullptr; const TransportSecurityPreload* foundEntry = nullptr; constchar* evalHost = hostname; constchar* evalPart; // Notice how the (xx = strchr) prevents pins for unqualified domain names. while (!foundEntry && (evalPart = strchr(evalHost, '.'))) {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Querying pinsets for host: '%s'\n", evalHost));
size_t foundEntryIndex; if (BinarySearchIf(kPublicKeyPinningPreloadList, 0,
std::size(kPublicKeyPinningPreloadList),
TransportSecurityPreloadBinarySearchComparator(evalHost),
&foundEntryIndex)) {
foundEntry = &kPublicKeyPinningPreloadList[foundEntryIndex];
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Found pinset for host: '%s'\n", evalHost)); if (evalHost != hostname) { if (!foundEntry->mIncludeSubdomains) { // Does not apply to this host, continue iterating
foundEntry = nullptr;
}
}
} else {
MOZ_LOG(gPublicKeyPinningLog, LogLevel::Debug,
("pkpin: Didn't find pinset for host: '%s'\n", evalHost));
} // Add one for '.'
evalHost = evalPart + 1;
}
// Returns true via the output parameter if the given certificate list meets // pinning requirements for the given host at the given time. It must be the // case that either there is an intersection between the set of hashes of // subject public key info data in the list and the most relevant non-expired // pinset for the host or there is no pinning information for the host. static nsresult CheckPinsForHostname( const nsTArray<Span<const uint8_t>>& certList, constchar* hostname, bool enforceTestMode, mozilla::pkix::Time time, /*out*/ bool& chainHasValidPins, /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo) {
chainHasValidPins = false; if (certList.IsEmpty()) { return NS_ERROR_INVALID_ARG;
} if (!hostname || hostname[0] == 0) { return NS_ERROR_INVALID_ARG;
}
const TransportSecurityPreload* staticFingerprints = nullptr;
nsresult rv = FindPinningInformation(hostname, time, staticFingerprints); if (NS_FAILED(rv)) { return rv;
} // If we have no pinning information, the certificate chain trivially // validates with respect to pinning. if (!staticFingerprints) {
chainHasValidPins = true; return NS_OK;
} if (staticFingerprints) { bool enforceTestModeResult;
rv = EvalChain(certList, staticFingerprints->pinset, enforceTestModeResult); if (NS_FAILED(rv)) { return rv;
}
chainHasValidPins = enforceTestModeResult; if (staticFingerprints->mTestMode && !enforceTestMode) {
chainHasValidPins = true;
}
if (pinningTelemetryInfo) { // If and only if a static entry is a Mozilla entry, it has a telemetry // ID. if ((staticFingerprints->mIsMoz &&
staticFingerprints->mId == kUnknownId) ||
(!staticFingerprints->mIsMoz &&
staticFingerprints->mId != kUnknownId)) { return NS_ERROR_FAILURE;
}
Telemetry::HistogramID histogram;
int32_t bucket; // We can collect per-host pinning violations for this host because it is // operationally critical to Firefox. if (staticFingerprints->mIsMoz) {
histogram = staticFingerprints->mTestMode
? Telemetry::CERT_PINNING_MOZ_TEST_RESULTS_BY_HOST
: Telemetry::CERT_PINNING_MOZ_RESULTS_BY_HOST;
bucket = staticFingerprints->mId * 2 + (enforceTestModeResult ? 1 : 0);
} else {
histogram = staticFingerprints->mTestMode
? Telemetry::CERT_PINNING_TEST_RESULTS
: Telemetry::CERT_PINNING_RESULTS;
bucket = enforceTestModeResult ? 1 : 0;
}
pinningTelemetryInfo->accumulateResult = true;
pinningTelemetryInfo->certPinningResultHistogram = Some(histogram);
pinningTelemetryInfo->certPinningResultBucket = bucket;
// We only collect per-CA pinning statistics upon failures. if (!enforceTestModeResult) {
int32_t binNumber = RootCABinNumber(certList.LastElement()); if (binNumber != ROOT_CERTIFICATE_UNKNOWN) {
pinningTelemetryInfo->accumulateForRoot = true;
pinningTelemetryInfo->rootBucket = binNumber;
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.