diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
commit | 40a355a42d4a9444dc753c04c6608dade2f06a23 (patch) | |
tree | 871fc667d2de662f171103ce5ec067014ef85e61 /netwerk/protocol/http/WebTransportCertificateVerifier.cpp | |
parent | Adding upstream version 124.0.1. (diff) | |
download | firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.tar.xz firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.zip |
Adding upstream version 125.0.1.upstream/125.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'netwerk/protocol/http/WebTransportCertificateVerifier.cpp')
-rw-r--r-- | netwerk/protocol/http/WebTransportCertificateVerifier.cpp | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/netwerk/protocol/http/WebTransportCertificateVerifier.cpp b/netwerk/protocol/http/WebTransportCertificateVerifier.cpp new file mode 100644 index 0000000000..cc778640a1 --- /dev/null +++ b/netwerk/protocol/http/WebTransportCertificateVerifier.cpp @@ -0,0 +1,280 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "WebTransportCertificateVerifier.h" +#include "ScopedNSSTypes.h" +#include "nss/mozpkix/pkixutil.h" +#include "nss/mozpkix/pkixcheck.h" +#include "hasht.h" + +namespace mozilla::psm { + +class ServerCertHashesTrustDomain : public mozilla::pkix::TrustDomain { + public: + ServerCertHashesTrustDomain() = default; + + virtual mozilla::pkix::Result FindIssuer( + mozilla::pkix::Input encodedIssuerName, IssuerChecker& checker, + mozilla::pkix::Time time) override; + + virtual mozilla::pkix::Result GetCertTrust( + mozilla::pkix::EndEntityOrCA endEntityOrCA, + const mozilla::pkix::CertPolicyId& policy, + mozilla::pkix::Input candidateCertDER, + /*out*/ mozilla::pkix::TrustLevel& trustLevel) override; + + virtual mozilla::pkix::Result CheckSignatureDigestAlgorithm( + mozilla::pkix::DigestAlgorithm digestAlg, + mozilla::pkix::EndEntityOrCA endEntityOrCA, + mozilla::pkix::Time notBefore) override; + + virtual mozilla::pkix::Result CheckRSAPublicKeyModulusSizeInBits( + mozilla::pkix::EndEntityOrCA endEntityOrCA, + unsigned int modulusSizeInBits) override; + + virtual mozilla::pkix::Result VerifyRSAPKCS1SignedData( + mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm, + mozilla::pkix::Input signature, + mozilla::pkix::Input subjectPublicKeyInfo) override; + + virtual mozilla::pkix::Result VerifyRSAPSSSignedData( + mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm, + mozilla::pkix::Input signature, + mozilla::pkix::Input subjectPublicKeyInfo) override; + + virtual mozilla::pkix::Result CheckECDSACurveIsAcceptable( + mozilla::pkix::EndEntityOrCA endEntityOrCA, + mozilla::pkix::NamedCurve curve) override; + + virtual mozilla::pkix::Result VerifyECDSASignedData( + mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm, + mozilla::pkix::Input signature, + mozilla::pkix::Input subjectPublicKeyInfo) override; + + virtual mozilla::pkix::Result DigestBuf( + mozilla::pkix::Input item, mozilla::pkix::DigestAlgorithm digestAlg, + /*out*/ uint8_t* digestBuf, size_t digestBufLen) override; + + virtual mozilla::pkix::Result CheckValidityIsAcceptable( + mozilla::pkix::Time notBefore, mozilla::pkix::Time notAfter, + mozilla::pkix::EndEntityOrCA endEntityOrCA, + mozilla::pkix::KeyPurposeId keyPurpose) override; + + virtual mozilla::pkix::Result NetscapeStepUpMatchesServerAuth( + mozilla::pkix::Time notBefore, + /*out*/ bool& matches) override; + + virtual mozilla::pkix::Result CheckRevocation( + mozilla::pkix::EndEntityOrCA endEntityOrCA, + const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, + mozilla::pkix::Duration validityDuration, + /*optional*/ const mozilla::pkix::Input* stapledOCSPResponse, + /*optional*/ const mozilla::pkix::Input* aiaExtension, + /*optional*/ const mozilla::pkix::Input* sctExtension) override; + + virtual mozilla::pkix::Result IsChainValid( + const mozilla::pkix::DERArray& certChain, mozilla::pkix::Time time, + const mozilla::pkix::CertPolicyId& requiredPolicy) override; + + virtual void NoteAuxiliaryExtension( + mozilla::pkix::AuxiliaryExtension extension, + mozilla::pkix::Input extensionData) override; +}; + +mozilla::pkix::Result ServerCertHashesTrustDomain::FindIssuer( + mozilla::pkix::Input encodedIssuerName, IssuerChecker& checker, + mozilla::pkix::Time time) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +mozilla::pkix::Result ServerCertHashesTrustDomain::GetCertTrust( + mozilla::pkix::EndEntityOrCA endEntityOrCA, + const mozilla::pkix::CertPolicyId& policy, + mozilla::pkix::Input candidateCertDER, + /*out*/ mozilla::pkix::TrustLevel& trustLevel) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +mozilla::pkix::Result +ServerCertHashesTrustDomain::CheckSignatureDigestAlgorithm( + mozilla::pkix::DigestAlgorithm digestAlg, + mozilla::pkix::EndEntityOrCA endEntityOrCA, mozilla::pkix::Time notBefore) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +mozilla::pkix::Result +ServerCertHashesTrustDomain::CheckRSAPublicKeyModulusSizeInBits( + mozilla::pkix::EndEntityOrCA endEntityOrCA, + unsigned int modulusSizeInBits) { + return mozilla::pkix::Result:: + ERROR_UNSUPPORTED_KEYALG; // RSA is not supported for + // serverCertificateHashes, + // Chromium does only support it for an intermediate period due to spec + // change, we do not support it. +} + +mozilla::pkix::Result ServerCertHashesTrustDomain::VerifyRSAPKCS1SignedData( + mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm, + mozilla::pkix::Input signature, mozilla::pkix::Input subjectPublicKeyInfo) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +mozilla::pkix::Result ServerCertHashesTrustDomain::VerifyRSAPSSSignedData( + mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm, + mozilla::pkix::Input signature, mozilla::pkix::Input subjectPublicKeyInfo) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +mozilla::pkix::Result ServerCertHashesTrustDomain::CheckECDSACurveIsAcceptable( + mozilla::pkix::EndEntityOrCA endEntityOrCA, + mozilla::pkix::NamedCurve curve) { + return mozilla::pkix::Result::Success; +} + +mozilla::pkix::Result ServerCertHashesTrustDomain::VerifyECDSASignedData( + mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm, + mozilla::pkix::Input signature, mozilla::pkix::Input subjectPublicKeyInfo) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +mozilla::pkix::Result ServerCertHashesTrustDomain::DigestBuf( + mozilla::pkix::Input item, mozilla::pkix::DigestAlgorithm digestAlg, + /*out*/ uint8_t* digestBuf, size_t digestBufLen) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +mozilla::pkix::Result ServerCertHashesTrustDomain::CheckValidityIsAcceptable( + mozilla::pkix::Time notBefore, mozilla::pkix::Time notAfter, + mozilla::pkix::EndEntityOrCA endEntityOrCA, + mozilla::pkix::KeyPurposeId keyPurpose) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +mozilla::pkix::Result +ServerCertHashesTrustDomain::NetscapeStepUpMatchesServerAuth( + mozilla::pkix::Time notBefore, + /*out*/ bool& matches) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +mozilla::pkix::Result ServerCertHashesTrustDomain::CheckRevocation( + mozilla::pkix::EndEntityOrCA endEntityOrCA, + const mozilla::pkix::CertID& certID, mozilla::pkix::Time time, + mozilla::pkix::Duration validityDuration, + /*optional*/ const mozilla::pkix::Input* stapledOCSPResponse, + /*optional*/ const mozilla::pkix::Input* aiaExtension, + /*optional*/ const mozilla::pkix::Input* sctExtension) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +mozilla::pkix::Result ServerCertHashesTrustDomain::IsChainValid( + const mozilla::pkix::DERArray& certChain, mozilla::pkix::Time time, + const mozilla::pkix::CertPolicyId& requiredPolicy) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); + + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +} + +void ServerCertHashesTrustDomain::NoteAuxiliaryExtension( + mozilla::pkix::AuxiliaryExtension extension, + mozilla::pkix::Input extensionData) { + MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); +} + +} // namespace mozilla::psm + +namespace mozilla::net { +// Does certificate verificate as required for serverCertificateHashes +// This function is currently only used for Quic, but may be used later also for +// http/2 +mozilla::pkix::Result AuthCertificateWithServerCertificateHashes( + nsTArray<uint8_t>& peerCert, + const nsTArray<RefPtr<nsIWebTransportHash>>& aServerCertHashes) { + using namespace mozilla::pkix; + Input certDER; + mozilla::pkix::Result rv = + certDER.Init(peerCert.Elements(), peerCert.Length()); + if (rv != Success) { + return rv; + } + BackCert cert(certDER, EndEntityOrCA::MustBeEndEntity, nullptr); + rv = cert.Init(); + if (rv != Success) { + return rv; + } + + Time notBefore(Time::uninitialized); + Time notAfter(Time::uninitialized); + rv = ParseValidity(cert.GetValidity(), ¬Before, ¬After); + if (rv != Success) { + return rv; + } + // now we check that validity is not greater than 14 days + Duration certDuration(notBefore, notAfter); + if (certDuration > Duration(60 * 60 * 24 * 14)) { + return mozilla::pkix::Result::ERROR_VALIDITY_TOO_LONG; + } + Time now = Now(); + // and if the certificate is actually valid? + rv = CheckValidity(now, notBefore, notAfter); + if (rv != Success) { + return rv; + } + + mozilla::psm::ServerCertHashesTrustDomain trustDomain; + rv = CheckSubjectPublicKeyInfo( + cert.GetSubjectPublicKeyInfo(), trustDomain, + EndEntityOrCA::MustBeEndEntity /* should be ignored*/); + if (rv != Success) { + return rv; + } + + // ok now the final check, calculate the hash and compare it: + // https://w3c.github.io/webtransport/#compute-a-certificate-hash + nsTArray<uint8_t> certHash; + if (NS_FAILED(Digest::DigestBuf(SEC_OID_SHA256, peerCert, certHash)) || + certHash.Length() != SHA256_LENGTH) { + return mozilla::pkix::Result::ERROR_INVALID_ALGORITHM; + } + + // https://w3c.github.io/webtransport/#verify-a-certificate-hash + for (const auto& hash : aServerCertHashes) { + nsCString algorithm; + if (NS_FAILED(hash->GetAlgorithm(algorithm)) || algorithm != "sha-256") { + continue; + } + + nsTArray<uint8_t> value; + if (NS_FAILED(hash->GetValue(value))) { + continue; + } + + if (certHash == value) { + return Success; + } + } + return mozilla::pkix::Result::ERROR_UNTRUSTED_CERT; +} +} // namespace mozilla::net |