diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /security/nss/gtests/mozpkix_gtest/pkixcert_signature_algorithm_tests.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/gtests/mozpkix_gtest/pkixcert_signature_algorithm_tests.cpp')
-rw-r--r-- | security/nss/gtests/mozpkix_gtest/pkixcert_signature_algorithm_tests.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/security/nss/gtests/mozpkix_gtest/pkixcert_signature_algorithm_tests.cpp b/security/nss/gtests/mozpkix_gtest/pkixcert_signature_algorithm_tests.cpp new file mode 100644 index 0000000000..fd1ab6c950 --- /dev/null +++ b/security/nss/gtests/mozpkix_gtest/pkixcert_signature_algorithm_tests.cpp @@ -0,0 +1,309 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +#include "pkixgtest.h" + +#include "mozpkix/pkixder.h" + +#include "secoid.h" + +using namespace mozilla::pkix; +using namespace mozilla::pkix::test; + +/* These tests generate invalid certificates on the fly, We want to test + * validation of those certificates, not the generation, so we + * need to temporarily allow disallowed signature policies before + * we do the actual certificate or ocsp signing + */ +class HashAlgorithmPolicies +{ + static const int numberOfHashes = 4; /* sigh */ + static const SECOidTag hashOids[numberOfHashes]; + + PRUint32 savedPolicy[numberOfHashes]; + +public: + void EnableHashSignaturePolicy(void); + void RestoreHashSignaturePolicy(void); +}; + +const SECOidTag HashAlgorithmPolicies::hashOids[numberOfHashes] = { + SEC_OID_MD2, + SEC_OID_MD4, + SEC_OID_MD5, + SEC_OID_SHA1 }; + +void +HashAlgorithmPolicies::EnableHashSignaturePolicy(void) +{ + for (int i=0;i < numberOfHashes; i++) { + ASSERT_EQ(SECSuccess, + NSS_GetAlgorithmPolicy(hashOids[i], &savedPolicy[i])); + ASSERT_EQ(SECSuccess, + NSS_SetAlgorithmPolicy(hashOids[i], NSS_USE_ALG_IN_SIGNATURE, 0)); + } +} + +void +HashAlgorithmPolicies::RestoreHashSignaturePolicy(void) +{ + for (int i=0;i < numberOfHashes; i++) { + ASSERT_EQ(SECSuccess, + NSS_SetAlgorithmPolicy(hashOids[i], savedPolicy[i], + NSS_USE_ALG_IN_SIGNATURE)); + } +} + +static ByteString +CreateCert(const char* issuerCN, + const char* subjectCN, + EndEntityOrCA endEntityOrCA, + const TestSignatureAlgorithm& signatureAlgorithm, + /*out*/ ByteString& subjectDER) +{ + static long serialNumberValue = 0; + ++serialNumberValue; + ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue)); + EXPECT_FALSE(ENCODING_FAILED(serialNumber)); + + ByteString issuerDER(CNToDERName(issuerCN)); + EXPECT_FALSE(ENCODING_FAILED(issuerDER)); + subjectDER = CNToDERName(subjectCN); + EXPECT_FALSE(ENCODING_FAILED(subjectDER)); + + ByteString extensions[2]; + if (endEntityOrCA == EndEntityOrCA::MustBeCA) { + extensions[0] = + CreateEncodedBasicConstraints(true, nullptr, Critical::Yes); + EXPECT_FALSE(ENCODING_FAILED(extensions[0])); + } + + ScopedTestKeyPair reusedKey(CloneReusedKeyPair()); + HashAlgorithmPolicies policies; + policies.EnableHashSignaturePolicy(); + ByteString certDER(CreateEncodedCertificate(v3, signatureAlgorithm, + serialNumber, issuerDER, + oneDayBeforeNow, oneDayAfterNow, + subjectDER, *reusedKey, + extensions, *reusedKey, + signatureAlgorithm)); + policies.RestoreHashSignaturePolicy(); + EXPECT_FALSE(ENCODING_FAILED(certDER)); + return certDER; +} + + +class AlgorithmTestsTrustDomain final : public DefaultCryptoTrustDomain +{ +public: + AlgorithmTestsTrustDomain(const ByteString& aRootDER, + const ByteString& aRootSubjectDER, + /*optional*/ const ByteString& aIntDER, + /*optional*/ const ByteString& aIntSubjectDER) + : rootDER(aRootDER) + , rootSubjectDER(aRootSubjectDER) + , intDER(aIntDER) + , intSubjectDER(aIntSubjectDER) + { + } + +private: + Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert, + /*out*/ TrustLevel& trustLevel) override + { + if (InputEqualsByteString(candidateCert, rootDER)) { + trustLevel = TrustLevel::TrustAnchor; + } else { + trustLevel = TrustLevel::InheritsTrust; + } + return Success; + } + + Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, Time) + override + { + ByteString* issuerDER = nullptr; + if (InputEqualsByteString(encodedIssuerName, rootSubjectDER)) { + issuerDER = &rootDER; + } else if (InputEqualsByteString(encodedIssuerName, intSubjectDER)) { + issuerDER = &intDER; + } else { + // FindIssuer just returns success if it can't find a potential issuer. + return Success; + } + Input issuerCert; + Result rv = issuerCert.Init(issuerDER->data(), issuerDER->length()); + if (rv != Success) { + return rv; + } + bool keepGoing; + return checker.Check(issuerCert, nullptr, keepGoing); + } + + Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, + const Input*, const Input*, const Input*) override + { + return Success; + } + + Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override + { + return Success; + } + + ByteString rootDER; + ByteString rootSubjectDER; + ByteString intDER; + ByteString intSubjectDER; +}; + +static const TestSignatureAlgorithm NO_INTERMEDIATE +{ + TestPublicKeyAlgorithm(ByteString()), + TestDigestAlgorithmID::MD2, + ByteString(), + false +}; + +struct ChainValidity final +{ + ChainValidity(const TestSignatureAlgorithm& aEndEntitySignatureAlgorithm, + const TestSignatureAlgorithm& aOptionalIntSignatureAlgorithm, + const TestSignatureAlgorithm& aRootSignatureAlgorithm, + bool aIsValid) + : endEntitySignatureAlgorithm(aEndEntitySignatureAlgorithm) + , optionalIntermediateSignatureAlgorithm(aOptionalIntSignatureAlgorithm) + , rootSignatureAlgorithm(aRootSignatureAlgorithm) + , isValid(aIsValid) + { } + + // In general, a certificate is generated for each of these. However, if + // optionalIntermediateSignatureAlgorithm is NO_INTERMEDIATE, then only 2 + // certificates are generated. + // The certificate generated for the given rootSignatureAlgorithm is the + // trust anchor. + TestSignatureAlgorithm endEntitySignatureAlgorithm; + TestSignatureAlgorithm optionalIntermediateSignatureAlgorithm; + TestSignatureAlgorithm rootSignatureAlgorithm; + bool isValid; +}; + +static const ChainValidity CHAIN_VALIDITY[] = +{ + // The trust anchor may have a signature with an unsupported signature + // algorithm. + ChainValidity(sha256WithRSAEncryption(), + NO_INTERMEDIATE, + md5WithRSAEncryption(), + true), + ChainValidity(sha256WithRSAEncryption(), + NO_INTERMEDIATE, + md2WithRSAEncryption(), + true), + + // Certificates that are not trust anchors must not have a signature with an + // unsupported signature algorithm. + ChainValidity(md5WithRSAEncryption(), + NO_INTERMEDIATE, + sha256WithRSAEncryption(), + false), + ChainValidity(md2WithRSAEncryption(), + NO_INTERMEDIATE, + sha256WithRSAEncryption(), + false), + ChainValidity(md2WithRSAEncryption(), + NO_INTERMEDIATE, + md5WithRSAEncryption(), + false), + ChainValidity(sha256WithRSAEncryption(), + md5WithRSAEncryption(), + sha256WithRSAEncryption(), + false), + ChainValidity(sha256WithRSAEncryption(), + md2WithRSAEncryption(), + sha256WithRSAEncryption(), + false), + ChainValidity(sha256WithRSAEncryption(), + md2WithRSAEncryption(), + md5WithRSAEncryption(), + false), +}; + +class pkixcert_IsValidChainForAlgorithm + : public ::testing::Test + , public ::testing::WithParamInterface<ChainValidity> +{ +}; + +::std::ostream& operator<<(::std::ostream& os, + const pkixcert_IsValidChainForAlgorithm&) +{ + return os << "TODO (bug 1318770)"; +} + +::std::ostream& operator<<(::std::ostream& os, const ChainValidity&) +{ + return os << "TODO (bug 1318770)"; +} + +TEST_P(pkixcert_IsValidChainForAlgorithm, IsValidChainForAlgorithm) +{ + const ChainValidity& chainValidity(GetParam()); + const char* rootCN = "CN=Root"; + ByteString rootSubjectDER; + ByteString rootEncoded( + CreateCert(rootCN, rootCN, EndEntityOrCA::MustBeCA, + chainValidity.rootSignatureAlgorithm, rootSubjectDER)); + EXPECT_FALSE(ENCODING_FAILED(rootEncoded)); + EXPECT_FALSE(ENCODING_FAILED(rootSubjectDER)); + + const char* issuerCN = rootCN; + + const char* intermediateCN = "CN=Intermediate"; + ByteString intermediateSubjectDER; + ByteString intermediateEncoded; + + // If the the algorithmIdentifier is empty, then it's NO_INTERMEDIATE. + if (!chainValidity.optionalIntermediateSignatureAlgorithm + .algorithmIdentifier.empty()) { + intermediateEncoded = + CreateCert(rootCN, intermediateCN, EndEntityOrCA::MustBeCA, + chainValidity.optionalIntermediateSignatureAlgorithm, + intermediateSubjectDER); + EXPECT_FALSE(ENCODING_FAILED(intermediateEncoded)); + EXPECT_FALSE(ENCODING_FAILED(intermediateSubjectDER)); + issuerCN = intermediateCN; + } + + AlgorithmTestsTrustDomain trustDomain(rootEncoded, rootSubjectDER, + intermediateEncoded, + intermediateSubjectDER); + + const char* endEntityCN = "CN=End Entity"; + ByteString endEntitySubjectDER; + ByteString endEntityEncoded( + CreateCert(issuerCN, endEntityCN, EndEntityOrCA::MustBeEndEntity, + chainValidity.endEntitySignatureAlgorithm, + endEntitySubjectDER)); + EXPECT_FALSE(ENCODING_FAILED(endEntityEncoded)); + EXPECT_FALSE(ENCODING_FAILED(endEntitySubjectDER)); + + Input endEntity; + ASSERT_EQ(Success, endEntity.Init(endEntityEncoded.data(), + endEntityEncoded.length())); + Result expectedResult = chainValidity.isValid + ? Success + : Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED; + ASSERT_EQ(expectedResult, + BuildCertChain(trustDomain, endEntity, Now(), + EndEntityOrCA::MustBeEndEntity, + KeyUsage::noParticularKeyUsageRequired, + KeyPurposeId::id_kp_serverAuth, + CertPolicyId::anyPolicy, nullptr)); +} + +INSTANTIATE_TEST_SUITE_P(pkixcert_IsValidChainForAlgorithm, + pkixcert_IsValidChainForAlgorithm, + testing::ValuesIn(CHAIN_VALIDITY)); |