/* -*- 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/. */
// Firefox currently does not advertise any RSA schemes for use // with Delegated Credentials. As a secondary (on top of NSS) // check, disallow any RSA SPKI here. When ssl_sig_rsa_pss_pss_* // schemes are supported, check the modulus size and allow RSA here. if (!isEcdsa) { return Result::ERROR_INVALID_KEY;
}
return Result::Success;
}
// The term "builtin root" traditionally refers to a root CA certificate that // has been added to the NSS trust store, because it has been approved // for inclusion according to the Mozilla CA policy, and might be accepted // by Mozilla applications as an issuer for certificates seen on the public web.
Result IsCertBuiltInRoot(Input certInput, bool& result) {
result = false;
if (NS_FAILED(BlockUntilLoadableCertsLoaded())) { return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
#ifdef DEBUG
nsCOMPtr<nsINSSComponent> component(do_GetService(PSM_COMPONENT_CONTRACTID)); if (!component) { return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
nsTArray<uint8_t> certBytes;
certBytes.AppendElements(certInput.UnsafeGetData(), certInput.GetLength()); if (NS_FAILED(component->IsCertTestBuiltInRoot(certBytes, &result))) { return Result::FATAL_ERROR_LIBRARY_FAILURE;
} if (result) { return Success;
} #endif// DEBUG
SECItem certItem(UnsafeMapInputToSECItem(certInput));
AutoSECMODListReadLock lock; for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
list = list->next) { for (int i = 0; i < list->module->slotCount; i++) {
PK11SlotInfo* slot = list->module->slots[i]; // We're searching for the "builtin root module", which is a module that // contains an object with a CKA_CLASS of CKO_NETSCAPE_BUILTIN_ROOT_LIST. // We use PK11_HasRootCerts() to identify a module with that property. // In the past, we exclusively used the PKCS#11 module named nssckbi, // which is provided by the NSS library. // Nowadays, some distributions use a replacement module, which contains // the builtin roots, but which also contains additional CA certificates, // such as CAs trusted in a local deployment. // We want to be able to distinguish between these two categories, // because a CA, which may issue certificates for the public web, // is expected to comply with additional requirements. // If the certificate has attribute CKA_NSS_MOZILLA_CA_POLICY set to true, // then we treat it as a "builtin root". if (!PK11_IsPresent(slot) || !PK11_HasRootCerts(slot)) { continue;
}
CK_OBJECT_HANDLE handle =
PK11_FindEncodedCertInSlot(slot, &certItem, nullptr); if (handle == CK_INVALID_HANDLE) { continue;
} if (PK11_HasAttributeSet(slot, handle, CKA_NSS_MOZILLA_CA_POLICY, false)) { // Attribute was found, and is set to true
result = true; break;
}
}
} return Success;
}
static Result BuildCertChainForOneKeyUsage(
NSSCertDBTrustDomain& trustDomain, Input certDER, Time time, KeyUsage ku1,
KeyUsage ku2, KeyUsage ku3, KeyPurposeId eku, const CertPolicyId& requiredPolicy, const Input* stapledOCSPResponse, /*optional out*/ CertVerifier::OCSPStaplingStatus* ocspStaplingStatus) {
trustDomain.ResetAccumulatedState();
Result rv =
BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
ku1, eku, requiredPolicy, stapledOCSPResponse); if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
trustDomain.ResetAccumulatedState();
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity, ku2, eku,
requiredPolicy, stapledOCSPResponse); if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
trustDomain.ResetAccumulatedState();
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity, ku3, eku,
requiredPolicy, stapledOCSPResponse); if (rv != Success) {
rv = Result::ERROR_INADEQUATE_KEY_USAGE;
}
}
} if (ocspStaplingStatus) {
*ocspStaplingStatus = trustDomain.GetOCSPStaplingStatus();
} return rv;
}
void CertVerifier::LoadKnownCTLogs() { if (mCTConfig.mMode == CertificateTransparencyMode::Disabled) { return;
}
mCTVerifier = MakeUnique<MultiLogCTVerifier>(); for (const CTLogInfo& log : kCTLogList) {
Input publicKey;
Result rv = publicKey.Init(
BitwiseCast<const uint8_t*, constchar*>(log.key), log.keyLength); if (rv != Success) {
MOZ_ASSERT_UNREACHABLE("Failed reading a log key for a known CT Log"); continue;
}
const CTLogOperatorInfo& logOperator =
kCTLogOperatorList[log.operatorIndex];
CTLogVerifier logVerifier(logOperator.id, log.state, log.timestamp);
rv = logVerifier.Init(publicKey); if (rv != Success) {
MOZ_ASSERT_UNREACHABLE("Failed initializing a known CT Log"); continue;
}
mCTVerifier->AddLog(std::move(logVerifier));
}
}
bool HostnameMatchesPolicy(constchar* hostname, const nsCString& policy) { // Some contexts don't have a hostname (mostly tests), in which case the // policy doesn't apply. if (!hostname) { returnfalse;
}
nsDependentCString hostnameString(hostname); // The policy is a comma-separated list of entries of the form // '.example.com', 'example.com', or an IP address. for (constauto& entry : policy.Split(',')) { if (entry.IsEmpty()) { continue;
} // For '.example.com' entries, exact matches match the policy. if (entry[0] == '.' &&
Substring(entry, 1).EqualsIgnoreCase(hostnameString)) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("not enforcing CT for '%s' (matches policy '%s')", hostname,
policy.get())); returntrue;
} // For 'example.com' entries, exact matches or subdomains match the policy // (IP addresses match here too). if (StringEndsWith(hostnameString, entry) &&
(hostnameString.Length() == entry.Length() ||
hostnameString[hostnameString.Length() - entry.Length() - 1] == '.')) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("not enforcing CT for '%s' (matches policy '%s')", hostname,
policy.get())); returntrue;
}
} returnfalse;
}
bool CertificateListHasSPKIHashIn( const nsTArray<nsTArray<uint8_t>>& certificates, const nsTArray<CopyableTArray<uint8_t>>& spkiHashes) { if (spkiHashes.IsEmpty()) { returnfalse;
} for (constauto& certificate : certificates) {
Input certificateInput; if (certificateInput.Init(certificate.Elements(), certificate.Length()) !=
Success) { returnfalse;
} // No path building is happening here, so this parameter doesn't matter.
EndEntityOrCA notUsedForPathBuilding = EndEntityOrCA::MustBeEndEntity;
BackCert decodedCertificate(certificateInput, notUsedForPathBuilding,
nullptr); if (decodedCertificate.Init() != Success) { returnfalse;
}
Input spki(decodedCertificate.GetSubjectPublicKeyInfo());
uint8_t spkiHash[SHA256_LENGTH]; if (DigestBufNSS(spki, DigestAlgorithm::sha256, spkiHash, sizeof(spkiHash)) != Success) { returnfalse;
}
Span spkiHashSpan(reinterpret_cast<const uint8_t*>(spkiHash), sizeof(spkiHash)); for (constauto& candidateSPKIHash : spkiHashes) { if (Span(candidateSPKIHash) == spkiHashSpan) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("found SPKI hash match - not enforcing CT")); returntrue;
}
}
} returnfalse;
}
Result CertVerifier::VerifyCertificateTransparencyPolicy(
NSSCertDBTrustDomain& trustDomain, const nsTArray<nsTArray<uint8_t>>& builtChain, Input sctsFromTLS, Time time, constchar* hostname, /*optional out*/ CertificateTransparencyInfo* ctInfo) { if (builtChain.IsEmpty()) { return Result::FATAL_ERROR_INVALID_ARGS;
} if (ctInfo) {
ctInfo->Reset();
} if (mCTConfig.mMode == CertificateTransparencyMode::Disabled ||
!trustDomain.GetIsBuiltChainRootBuiltInRoot()) { return Success;
} if (time > TimeFromEpochInSeconds(kCTExpirationTime / PR_USEC_PER_SEC)) {
MOZ_LOG(gCertVerifierLog, LogLevel::Warning,
("skipping CT - built-in information has expired")); return Success;
} if (ctInfo) {
ctInfo->enabled = true;
}
Result rv = VerifyCertificateTransparencyPolicyInner(
trustDomain, builtChain, sctsFromTLS, time, ctInfo); if (rv == Result::ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY &&
(mCTConfig.mMode != CertificateTransparencyMode::Enforce ||
HostnameMatchesPolicy(hostname, mCTConfig.mSkipForHosts) ||
CertificateListHasSPKIHashIn(builtChain,
mCTConfig.mSkipForSPKIHashes))) { return Success;
}
return rv;
}
Result CertVerifier::VerifyCertificateTransparencyPolicyInner(
NSSCertDBTrustDomain& trustDomain, const nsTArray<nsTArray<uint8_t>>& builtChain, Input sctsFromTLS, Time time, /*optional out*/ CertificateTransparencyInfo* ctInfo) {
Input embeddedSCTs = trustDomain.GetSCTListFromCertificate(); if (embeddedSCTs.GetLength() > 0) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("Got embedded SCT data of length %zu\n", static_cast<size_t>(embeddedSCTs.GetLength())));
}
Input sctsFromOCSP = trustDomain.GetSCTListFromOCSPStapling(); if (sctsFromOCSP.GetLength() > 0) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("Got OCSP SCT data of length %zu\n", static_cast<size_t>(sctsFromOCSP.GetLength())));
} if (sctsFromTLS.GetLength() > 0) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("Got TLS SCT data of length %zu\n", static_cast<size_t>(sctsFromTLS.GetLength())));
}
if (builtChain.Length() == 1) { // Issuer certificate is required for SCT verification. // If we've arrived here, we probably have a "trust chain" with only one // certificate (i.e. a self-signed end-entity that has been set as a trust // anchor either by a third party modifying our trust DB or via the // enterprise roots feature). If this is the case, certificate transparency // information will probably not be present, and it certainly won't verify // correctly. To simplify things, we return an empty CTVerifyResult and a // "not enough SCTs" CTPolicyCompliance result. if (ctInfo) {
CTVerifyResult emptyResult;
ctInfo->verifyResult = std::move(emptyResult);
ctInfo->policyCompliance.emplace(CTPolicyCompliance::NotEnoughScts);
} return Result::ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY;
}
const nsTArray<uint8_t>& endEntityBytes = builtChain.ElementAt(0);
Input endEntityInput;
Result rv =
endEntityInput.Init(endEntityBytes.Elements(), endEntityBytes.Length()); if (rv != Success) { return rv;
}
switch (usage) { case certificateUsageSSLClient: { // XXX: We don't really have a trust bit for SSL client authentication so // just use trustEmail as it is the closest alternative.
NSSCertDBTrustDomain trustDomain(
trustEmail, defaultOCSPFetching, mOCSPCache, mSignatureCache.get(),
mTrustCache.get(), pinArg, mOCSPTimeoutSoft, mOCSPTimeoutHard,
mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, NetscapeStepUpPolicy::NeverMatch,
mCRLiteMode, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
rv = BuildCertChain(
trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature, KeyPurposeId::id_kp_clientAuth,
CertPolicyId::anyPolicy, stapledOCSPResponse); if (madeOCSPRequests) {
*madeOCSPRequests |=
trustDomain.GetOCSPFetchStatus() == OCSPFetchStatus::Fetched;
} break;
}
case certificateUsageSSLServer: { // TODO: When verifying a certificate in an SSL handshake, we should // restrict the acceptable key usage based on the key exchange method // chosen by the server.
// Try to validate for EV first.
NSSCertDBTrustDomain::OCSPFetching evOCSPFetching =
(mOCSPDownloadConfig == ocspOff) || (flags & FLAG_LOCAL_ONLY)
? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
: NSSCertDBTrustDomain::FetchOCSPForEV;
for (size_t i = 0; i < keySizeOptionsCount && rv != Success; i++) { // invalidate any telemetry info relating to failed chains if (pinningTelemetryInfo) {
pinningTelemetryInfo->Reset();
}
NSSCertDBTrustDomain trustDomain(
trustSSL, defaultOCSPFetching, mOCSPCache, mSignatureCache.get(),
mTrustCache.get(), pinArg, mOCSPTimeoutSoft, mOCSPTimeoutHard,
mCertShortLifetimeInDays, keySizeOptions[i],
ValidityCheckingMode::CheckingOff, mNetscapeStepUpPolicy,
mCRLiteMode, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain,
pinningTelemetryInfo, hostname);
rv = BuildCertChainForOneKeyUsage(
trustDomain, certDER, time,
KeyUsage::digitalSignature, //(EC)DHE
KeyUsage::keyEncipherment, // RSA
KeyUsage::keyAgreement, //(EC)DH
KeyPurposeId::id_kp_serverAuth, CertPolicyId::anyPolicy,
stapledOCSPResponse, ocspStaplingStatus); if (madeOCSPRequests) {
*madeOCSPRequests |=
trustDomain.GetOCSPFetchStatus() == OCSPFetchStatus::Fetched;
} if (issuerSources) {
*issuerSources = trustDomain.GetIssuerSources();
} if (rv != Success && !IsFatalError(rv) &&
rv != Result::ERROR_REVOKED_CERTIFICATE &&
trustDomain.GetIsErrorDueToDistrustedCAPolicy()) { // Bug 1444440 - If there are multiple paths, at least one to a CA // distrusted-by-policy, and none of them ending in a trusted root, // then we might show a different error (UNKNOWN_ISSUER) than we // intend, confusing users.
rv = Result::ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED;
} if (rv == Success) {
rv = VerifyCertificateTransparencyPolicy(trustDomain, builtChain,
sctsFromTLSInput, time,
hostname, ctInfo);
} if (rv == Success) { if (keySizeStatus) {
*keySizeStatus = keySizeStatuses[i];
} if (isBuiltChainRootBuiltInRoot) {
*isBuiltChainRootBuiltInRoot =
trustDomain.GetIsBuiltChainRootBuiltInRoot();
} break;
}
}
case certificateUsageEmailRecipient: { // TODO: The higher level S/MIME processing should pass in which key // usage it is trying to verify for, and base its algorithm choices // based on the result of the verification(s).
NSSCertDBTrustDomain trustDomain(
trustEmail, defaultOCSPFetching, mOCSPCache, mSignatureCache.get(),
mTrustCache.get(), pinArg, mOCSPTimeoutSoft, mOCSPTimeoutHard,
mCertShortLifetimeInDays, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff, NetscapeStepUpPolicy::NeverMatch,
mCRLiteMode, originAttributes, mThirdPartyRootInputs,
mThirdPartyIntermediateInputs, extraCertificates, builtChain, nullptr,
nullptr);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::keyEncipherment, // RSA
KeyPurposeId::id_kp_emailProtection,
CertPolicyId::anyPolicy, stapledOCSPResponse); if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::keyAgreement, // ECDH/DH
KeyPurposeId::id_kp_emailProtection,
CertPolicyId::anyPolicy, stapledOCSPResponse);
} if (madeOCSPRequests) {
*madeOCSPRequests |=
trustDomain.GetOCSPFetchStatus() == OCSPFetchStatus::Fetched;
} break;
}
nsTArray<Span<const uint8_t>> emptyCertList; // AppTrustDomain is only used for its signature verification callbacks // (AppTrustDomain::Verify{ECDSA,RSAPKCS1,RSAPSS}SignedData).
mozilla::psm::AppTrustDomain trustDomain(std::move(emptyCertList));
Result rv = VerifySignedData(trustDomain, backCert.GetSignedData(),
backCert.GetSubjectPublicKeyInfo()); return rv == Success;
}
static Result CheckCertHostnameHelper(Input peerCertInput, const nsACString& hostname, bool rootIsBuiltIn) {
Input hostnameInput;
Result rv = hostnameInput.Init(
BitwiseCast<const uint8_t*, constchar*>(hostname.BeginReading()),
hostname.Length()); if (rv != Success) { return Result::FATAL_ERROR_INVALID_ARGS;
}
SkipInvalidSANsForNonBuiltInRootsPolicy nameMatchingPolicy(rootIsBuiltIn);
rv = CheckCertHostname(peerCertInput, hostnameInput, nameMatchingPolicy); // Treat malformed name information as a domain mismatch. if (rv == Result::ERROR_BAD_DER) { return Result::ERROR_BAD_CERT_DOMAIN;
} return rv;
}
if (isBuiltChainRootBuiltInRoot) {
*isBuiltChainRootBuiltInRoot = false;
}
if (evStatus) {
*evStatus = EVStatus::NotEV;
}
if (hostname.IsEmpty()) { return Result::FATAL_ERROR_INVALID_ARGS;
}
// CreateCertErrorRunnable assumes that CheckCertHostname is only called // if VerifyCert succeeded.
Input peerCertInput;
Result rv =
peerCertInput.Init(peerCertBytes.Elements(), peerCertBytes.Length()); if (rv != Success) { return rv;
} bool isBuiltChainRootBuiltInRootLocal;
rv = VerifyCert(
peerCertBytes, certificateUsageSSLServer, time, pinarg,
PromiseFlatCString(hostname).get(), builtChain, flags, extraCertificates,
stapledOCSPResponse, sctsFromTLS, originAttributes, evStatus,
ocspStaplingStatus, keySizeStatus, pinningTelemetryInfo, ctInfo,
&isBuiltChainRootBuiltInRootLocal, madeOCSPRequests, issuerSources); if (rv != Success) { // we don't use the certificate for path building, so this parameter doesn't // matter
EndEntityOrCA notUsedForPaths = EndEntityOrCA::MustBeEndEntity;
BackCert peerBackCert(peerCertInput, notUsedForPaths, nullptr); if (peerBackCert.Init() != Success) { return rv;
} if ((rv == Result::ERROR_UNKNOWN_ISSUER ||
rv == Result::ERROR_BAD_SIGNATURE ||
rv == Result::ERROR_INADEQUATE_KEY_USAGE) &&
CertIsSelfSigned(peerBackCert, pinarg)) { // In this case we didn't find any issuer for the certificate, or we did // find other certificates with the same subject but different keys, and // the certificate is self-signed. return Result::ERROR_SELF_SIGNED_CERT;
} if (rv == Result::ERROR_UNKNOWN_ISSUER) { // In this case we didn't get any valid path for the cert. Let's see if // the issuer is the same as the issuer for our canary probe. If yes, this // connection is connecting via a misconfigured proxy. // Note: The MitM canary might not be set. In this case we consider this // an unknown issuer error.
nsCOMPtr<nsINSSComponent> component(
do_GetService(PSM_COMPONENT_CONTRACTID)); if (!component) { return Result::FATAL_ERROR_LIBRARY_FAILURE;
} // IssuerMatchesMitmCanary succeeds if the issuer matches the canary and // the feature is enabled.
Input issuerNameInput = peerBackCert.GetIssuer();
SECItem issuerNameItem = UnsafeMapInputToSECItem(issuerNameInput);
UniquePORTString issuerName(CERT_DerNameToAscii(&issuerNameItem)); if (!issuerName) { return Result::ERROR_BAD_DER;
}
nsresult rv = component->IssuerMatchesMitmCanary(issuerName.get()); if (NS_SUCCEEDED(rv)) { return Result::ERROR_MITM_DETECTED;
}
} // If the certificate is expired or not yet valid, first check whether or // not it is valid for the indicated hostname, because that would be a more // serious error. if (rv == Result::ERROR_EXPIRED_CERTIFICATE ||
rv == Result::ERROR_NOT_YET_VALID_CERTIFICATE ||
rv == Result::ERROR_INVALID_DER_TIME) {
Result hostnameResult =
CheckCertHostnameHelper(peerCertInput, hostname, false); if (hostnameResult != Success) { return hostnameResult;
}
} return rv;
}
if (dcInfo) {
rv = IsDelegatedCredentialAcceptable(*dcInfo); if (rv != Success) { return rv;
}
}
Input stapledOCSPResponseInput;
Input* responseInputPtr = nullptr; if (stapledOCSPResponse) {
rv = stapledOCSPResponseInput.Init(stapledOCSPResponse->Elements(),
stapledOCSPResponse->Length()); if (rv != Success) { // The stapled OCSP response was too big. return Result::ERROR_OCSP_MALFORMED_RESPONSE;
}
responseInputPtr = &stapledOCSPResponseInput;
}
if (!(flags & FLAG_TLS_IGNORE_STATUS_REQUEST)) {
rv = CheckTLSFeaturesAreSatisfied(peerCertInput, responseInputPtr); if (rv != Success) { return rv;
}
}
// Take the (data, signature, subjectPublicKeyInfo, publicKeyAlgorithm, // digestAlgorithm) tuple that defines a signature and derive a hash that // uniquely identifies it. This is done by prefixing each variable-length // component (data, signature, and subjectPublicKeyInfo) with // sizeof(pkix::Input::size_type) bytes (currently 2) indicating the length of // that component and concatenating them together, followed by one byte for the // digestAlgorithm. The concatenation is then hashed with sha512. // It should be computationally infeasible to find two distinct sets of inputs // that have the same sha512 hash (and if it were possible, then it would be // possible to break the signature scheme itself). void HashSignatureParams(pkix::Input data, pkix::Input signature,
pkix::Input subjectPublicKeyInfo,
pkix::der::PublicKeyAlgorithm publicKeyAlgorithm,
pkix::DigestAlgorithm digestAlgorithm, /*out*/ Maybe<nsTArray<uint8_t>>& sha512Hash) {
sha512Hash.reset();
Digest digest; if (NS_FAILED(digest.Begin(SEC_OID_SHA512))) { return;
}
pkix::Input::size_type dataLength = data.GetLength(); if (NS_FAILED(digest.Update(reinterpret_cast<const uint8_t*>(&dataLength), sizeof(dataLength)))) { return;
} if (NS_FAILED(digest.Update(data.UnsafeGetData(), dataLength))) { return;
}
pkix::Input::size_type signatureLength = signature.GetLength(); if (NS_FAILED(
digest.Update(reinterpret_cast<const uint8_t*>(&signatureLength), sizeof(signatureLength)))) { return;
} if (NS_FAILED(digest.Update(signature.UnsafeGetData(), signatureLength))) { return;
}
pkix::Input::size_type spkiLength = subjectPublicKeyInfo.GetLength(); if (NS_FAILED(digest.Update(reinterpret_cast<const uint8_t*>(&spkiLength), sizeof(spkiLength)))) { return;
} if (NS_FAILED(
digest.Update(subjectPublicKeyInfo.UnsafeGetData(), spkiLength))) { return;
} if (NS_FAILED(
digest.Update(reinterpret_cast<const uint8_t*>(&publicKeyAlgorithm), sizeof(publicKeyAlgorithm)))) { return;
} if (NS_FAILED(
digest.Update(reinterpret_cast<const uint8_t*>(&digestAlgorithm), sizeof(digestAlgorithm)))) { return;
}
nsTArray<uint8_t> result; if (NS_FAILED(digest.End(result))) { return;
}
sha512Hash.emplace(std::move(result));
}
Result VerifySignedDataWithCache(
der::PublicKeyAlgorithm publicKeyAlg,
mozilla::glean::impl::DenominatorMetric telemetryDenominator,
mozilla::glean::impl::NumeratorMetric telemetryNumerator, Input data,
DigestAlgorithm digestAlgorithm, Input signature,
Input subjectPublicKeyInfo, SignatureCache* signatureCache, void* pinArg) {
telemetryDenominator.Add(1);
Maybe<nsTArray<uint8_t>> sha512Hash;
HashSignatureParams(data, signature, subjectPublicKeyInfo, publicKeyAlg,
digestAlgorithm, sha512Hash); // If hashing the signature parameters succeeded, see if this signature is in // the signature cache. if (sha512Hash.isSome() &&
signature_cache_get(signatureCache, sha512Hash.ref().Elements())) {
telemetryNumerator.AddToNumerator(1); return Success;
}
Result result; switch (publicKeyAlg) { case der::PublicKeyAlgorithm::ECDSA:
result = VerifyECDSASignedDataNSS(data, digestAlgorithm, signature,
subjectPublicKeyInfo, pinArg); break; case der::PublicKeyAlgorithm::RSA_PKCS1:
result = VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm, signature,
subjectPublicKeyInfo, pinArg); break; case der::PublicKeyAlgorithm::RSA_PSS:
result = VerifyRSAPSSSignedDataNSS(data, digestAlgorithm, signature,
subjectPublicKeyInfo, pinArg); break; default:
MOZ_ASSERT_UNREACHABLE("unhandled public key algorithm"); return Result::FATAL_ERROR_LIBRARY_FAILURE;
} // Add this signature to the signature cache. if (sha512Hash.isSome() && result == Success) {
signature_cache_insert(signatureCache, sha512Hash.ref().Elements());
} return result;
}
} // namespace psm
} // namespace mozilla
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet)
¤
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.