summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/mozpkix_gtest/pkixcert_extension_tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/gtests/mozpkix_gtest/pkixcert_extension_tests.cpp')
-rw-r--r--security/nss/gtests/mozpkix_gtest/pkixcert_extension_tests.cpp276
1 files changed, 276 insertions, 0 deletions
diff --git a/security/nss/gtests/mozpkix_gtest/pkixcert_extension_tests.cpp b/security/nss/gtests/mozpkix_gtest/pkixcert_extension_tests.cpp
new file mode 100644
index 000000000..762fac146
--- /dev/null
+++ b/security/nss/gtests/mozpkix_gtest/pkixcert_extension_tests.cpp
@@ -0,0 +1,276 @@
+/* -*- 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 code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pkixgtest.h"
+
+#include "mozpkix/pkixder.h"
+#include "mozpkix/test/pkixtestutil.h"
+
+using namespace mozilla::pkix;
+using namespace mozilla::pkix::test;
+
+// Creates a self-signed certificate with the given extension.
+static ByteString
+CreateCertWithExtensions(const char* subjectCN,
+ const ByteString* extensions)
+{
+ static long serialNumberValue = 0;
+ ++serialNumberValue;
+ ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
+ EXPECT_FALSE(ENCODING_FAILED(serialNumber));
+ ByteString issuerDER(CNToDERName(subjectCN));
+ EXPECT_FALSE(ENCODING_FAILED(issuerDER));
+ ByteString subjectDER(CNToDERName(subjectCN));
+ EXPECT_FALSE(ENCODING_FAILED(subjectDER));
+ ScopedTestKeyPair subjectKey(CloneReusedKeyPair());
+ return CreateEncodedCertificate(v3, sha256WithRSAEncryption(),
+ serialNumber, issuerDER,
+ oneDayBeforeNow, oneDayAfterNow,
+ subjectDER, *subjectKey, extensions,
+ *subjectKey,
+ sha256WithRSAEncryption());
+}
+
+// Creates a self-signed certificate with the given extension.
+static ByteString
+CreateCertWithOneExtension(const char* subjectStr, const ByteString& extension)
+{
+ const ByteString extensions[] = { extension, ByteString() };
+ return CreateCertWithExtensions(subjectStr, extensions);
+}
+
+class TrustEverythingTrustDomain final : public DefaultCryptoTrustDomain
+{
+private:
+ Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input,
+ /*out*/ TrustLevel& trustLevel) override
+ {
+ trustLevel = TrustLevel::TrustAnchor;
+ return Success;
+ }
+
+ Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
+ /*optional*/ const Input*, /*optional*/ const Input*)
+ override
+ {
+ return Success;
+ }
+
+ Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override
+ {
+ return Success;
+ }
+};
+
+// python DottedOIDToCode.py --tlv unknownExtensionOID 1.3.6.1.4.1.13769.666.666.666.1.500.9.3
+static const uint8_t tlv_unknownExtensionOID[] = {
+ 0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a, 0x85, 0x1a,
+ 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03
+};
+
+// python DottedOIDToCode.py --tlv id-pe-authorityInformationAccess 1.3.6.1.5.5.7.1.1
+static const uint8_t tlv_id_pe_authorityInformationAccess[] = {
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
+};
+
+// python DottedOIDToCode.py --tlv wrongExtensionOID 1.3.6.6.1.5.5.7.1.1
+// (there is an extra "6" that shouldn't be in this OID)
+static const uint8_t tlv_wrongExtensionOID[] = {
+ 0x06, 0x09, 0x2b, 0x06, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
+};
+
+// python DottedOIDToCode.py --tlv id-ce-unknown 2.5.29.55
+// (this is a made-up OID for testing "id-ce"-prefixed OIDs that mozilla::pkix
+// doesn't handle)
+static const uint8_t tlv_id_ce_unknown[] = {
+ 0x06, 0x03, 0x55, 0x1d, 0x37
+};
+
+// python DottedOIDToCode.py --tlv id-ce-inhibitAnyPolicy 2.5.29.54
+static const uint8_t tlv_id_ce_inhibitAnyPolicy[] = {
+ 0x06, 0x03, 0x55, 0x1d, 0x36
+};
+
+// python DottedOIDToCode.py --tlv id-pkix-ocsp-nocheck 1.3.6.1.5.5.7.48.1.5
+static const uint8_t tlv_id_pkix_ocsp_nocheck[] = {
+ 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05
+};
+
+struct ExtensionTestcase
+{
+ ByteString extension;
+ Result expectedResult;
+};
+
+::std::ostream& operator<<(::std::ostream& os, const ExtensionTestcase&)
+{
+ return os << "TODO (bug 1318770)";
+}
+
+static const ExtensionTestcase EXTENSION_TESTCASES[] =
+{
+ // Tests that a non-critical extension not in the id-ce or id-pe arcs (which
+ // is thus unknown to us) verifies successfully even if empty (extensions we
+ // know about aren't normally allowed to be empty).
+ { TLV(der::SEQUENCE,
+ BytesToByteString(tlv_unknownExtensionOID) +
+ TLV(der::OCTET_STRING, ByteString())),
+ Success
+ },
+
+ // Tests that a critical extension not in the id-ce or id-pe arcs (which is
+ // thus unknown to us) is detected and that verification fails with the
+ // appropriate error.
+ { TLV(der::SEQUENCE,
+ BytesToByteString(tlv_unknownExtensionOID) +
+ Boolean(true) +
+ TLV(der::OCTET_STRING, ByteString())),
+ Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
+ },
+
+ // Tests that a id-pe-authorityInformationAccess critical extension
+ // is detected and that verification succeeds.
+ // XXX: According to RFC 5280 an AIA that consists of an empty sequence is
+ // not legal, but we accept it and that is not what we're testing here.
+ { TLV(der::SEQUENCE,
+ BytesToByteString(tlv_id_pe_authorityInformationAccess) +
+ Boolean(true) +
+ TLV(der::OCTET_STRING, TLV(der::SEQUENCE, ByteString()))),
+ Success
+ },
+
+ // Tests that an incorrect OID for id-pe-authorityInformationAccess
+ // (when marked critical) is detected and that verification fails.
+ // (Until bug 1020993 was fixed, this wrong value was used for
+ // id-pe-authorityInformationAccess.)
+ { TLV(der::SEQUENCE,
+ BytesToByteString(tlv_wrongExtensionOID) +
+ Boolean(true) +
+ TLV(der::OCTET_STRING, ByteString())),
+ Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
+ },
+
+ // We know about some id-ce extensions (OID arc 2.5.29), but not all of them.
+ // Tests that an unknown id-ce extension is detected and that verification
+ // fails.
+ { TLV(der::SEQUENCE,
+ BytesToByteString(tlv_id_ce_unknown) +
+ Boolean(true) +
+ TLV(der::OCTET_STRING, ByteString())),
+ Result::ERROR_UNKNOWN_CRITICAL_EXTENSION
+ },
+
+ // Tests that a certificate with a known critical id-ce extension (in this
+ // case, OID 2.5.29.54, which is id-ce-inhibitAnyPolicy), verifies
+ // successfully.
+ { TLV(der::SEQUENCE,
+ BytesToByteString(tlv_id_ce_inhibitAnyPolicy) +
+ Boolean(true) +
+ TLV(der::OCTET_STRING, Integer(0))),
+ Success
+ },
+
+ // Tests that a certificate with the id-pkix-ocsp-nocheck extension (marked
+ // critical) verifies successfully.
+ // RFC 6960:
+ // ext-ocsp-nocheck EXTENSION ::= { SYNTAX NULL IDENTIFIED
+ // BY id-pkix-ocsp-nocheck }
+ { TLV(der::SEQUENCE,
+ BytesToByteString(tlv_id_pkix_ocsp_nocheck) +
+ Boolean(true) +
+ TLV(der::OCTET_STRING, TLV(der::NULLTag, ByteString()))),
+ Success
+ },
+
+ // Tests that a certificate with another representation of the
+ // id-pkix-ocsp-nocheck extension (marked critical) verifies successfully.
+ // According to http://comments.gmane.org/gmane.ietf.x509/30947,
+ // some code creates certificates where value of the extension is
+ // an empty OCTET STRING.
+ { TLV(der::SEQUENCE,
+ BytesToByteString(tlv_id_pkix_ocsp_nocheck) +
+ Boolean(true) +
+ TLV(der::OCTET_STRING, ByteString())),
+ Success
+ },
+};
+
+class pkixcert_extension
+ : public ::testing::Test
+ , public ::testing::WithParamInterface<ExtensionTestcase>
+{
+protected:
+ static TrustEverythingTrustDomain trustDomain;
+};
+
+/*static*/ TrustEverythingTrustDomain pkixcert_extension::trustDomain;
+
+TEST_P(pkixcert_extension, ExtensionHandledProperly)
+{
+ const ExtensionTestcase& testcase(GetParam());
+ const char* cn = "Cert Extension Test";
+ ByteString cert(CreateCertWithOneExtension(cn, testcase.extension));
+ ASSERT_FALSE(ENCODING_FAILED(cert));
+ Input certInput;
+ ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
+ ASSERT_EQ(testcase.expectedResult,
+ BuildCertChain(trustDomain, certInput, Now(),
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::anyExtendedKeyUsage,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
+}
+
+INSTANTIATE_TEST_CASE_P(pkixcert_extension,
+ pkixcert_extension,
+ testing::ValuesIn(EXTENSION_TESTCASES));
+
+// Two subjectAltNames must result in an error.
+TEST_F(pkixcert_extension, DuplicateSubjectAltName)
+{
+ // python DottedOIDToCode.py --tlv id-ce-subjectAltName 2.5.29.17
+ static const uint8_t tlv_id_ce_subjectAltName[] = {
+ 0x06, 0x03, 0x55, 0x1d, 0x11
+ };
+
+ ByteString subjectAltName(
+ TLV(der::SEQUENCE,
+ BytesToByteString(tlv_id_ce_subjectAltName) +
+ TLV(der::OCTET_STRING, TLV(der::SEQUENCE, DNSName("example.com")))));
+ static const ByteString extensions[] = { subjectAltName, subjectAltName,
+ ByteString() };
+ static const char* certCN = "Cert With Duplicate subjectAltName";
+ ByteString cert(CreateCertWithExtensions(certCN, extensions));
+ ASSERT_FALSE(ENCODING_FAILED(cert));
+ Input certInput;
+ ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
+ ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID,
+ BuildCertChain(trustDomain, certInput, Now(),
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::anyExtendedKeyUsage,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
+}