summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/mozpkix_gtest/pkixcert_signature_algorithm_tests.cpp
diff options
context:
space:
mode:
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.cpp309
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));