summaryrefslogtreecommitdiffstats
path: root/src/lib/dns/tests/nsec3hash_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dns/tests/nsec3hash_unittest.cc')
-rw-r--r--src/lib/dns/tests/nsec3hash_unittest.cc269
1 files changed, 269 insertions, 0 deletions
diff --git a/src/lib/dns/tests/nsec3hash_unittest.cc b/src/lib/dns/tests/nsec3hash_unittest.cc
new file mode 100644
index 0000000..b47bb49
--- /dev/null
+++ b/src/lib/dns/tests/nsec3hash_unittest.cc
@@ -0,0 +1,269 @@
+// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// 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 <config.h>
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <dns/nsec3hash.h>
+#include <dns/labelsequence.h>
+#include <dns/rdataclass.h>
+#include <util/encode/hex.h>
+
+using boost::scoped_ptr;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::util;
+using namespace isc::util::encode;
+
+namespace {
+typedef scoped_ptr<NSEC3Hash> NSEC3HashPtr;
+
+// Commonly used NSEC3 suffix, defined to reduce the amount of typing
+const char* const nsec3_common = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
+
+class NSEC3HashTest : public ::testing::Test {
+protected:
+ NSEC3HashTest() :
+ test_hash(NSEC3Hash::create(generic::NSEC3PARAM("1 0 12 aabbccdd"))),
+ test_hash_nsec3(NSEC3Hash::create(generic::NSEC3
+ ("1 0 12 aabbccdd " +
+ string(nsec3_common))))
+ {
+ const uint8_t salt[] = {0xaa, 0xbb, 0xcc, 0xdd};
+ test_hash_args.reset(NSEC3Hash::create(1, 12, salt, sizeof(salt)));
+ }
+
+ ~NSEC3HashTest() {
+ // Make sure we reset the hash creator to the default
+ setNSEC3HashCreator(NULL);
+ }
+
+ // An NSEC3Hash object commonly used in tests. Parameters are borrowed
+ // from the RFC5155 example. Construction of this object implicitly
+ // checks a successful case of the creation.
+ NSEC3HashPtr test_hash;
+
+ // Similar to test_hash, but created from NSEC3 RR.
+ NSEC3HashPtr test_hash_nsec3;
+
+ // Similar to test_hash, but created from passed args.
+ NSEC3HashPtr test_hash_args;
+};
+
+TEST_F(NSEC3HashTest, unknownAlgorithm) {
+ EXPECT_THROW(NSEC3HashPtr(
+ NSEC3Hash::create(
+ generic::NSEC3PARAM("2 0 12 aabbccdd"))),
+ UnknownNSEC3HashAlgorithm);
+ EXPECT_THROW(NSEC3HashPtr(
+ NSEC3Hash::create(
+ generic::NSEC3("2 0 12 aabbccdd " +
+ string(nsec3_common)))),
+ UnknownNSEC3HashAlgorithm);
+
+ const uint8_t salt[] = {0xaa, 0xbb, 0xcc, 0xdd};
+ EXPECT_THROW(NSEC3HashPtr(NSEC3Hash::create(2, 12, salt, sizeof(salt))),
+ UnknownNSEC3HashAlgorithm);
+}
+
+// Common checks for NSEC3 hash calculation
+void
+calculateCheck(NSEC3Hash& hash) {
+ // A couple of normal cases from the RFC5155 example.
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ hash.calculate(Name("example")));
+ EXPECT_EQ("35MTHGPGCU1QG68FAB165KLNSNK3DPVL",
+ hash.calculate(Name("a.example")));
+
+ // Check case-insensitiveness
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ hash.calculate(Name("EXAMPLE")));
+
+ // Repeat for the LabelSequence variant.
+
+ // A couple of normal cases from the RFC5155 example.
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ hash.calculate(LabelSequence(Name("example"))));
+ EXPECT_EQ("35MTHGPGCU1QG68FAB165KLNSNK3DPVL",
+ hash.calculate(LabelSequence(Name("a.example"))));
+
+ // Check case-insensitiveness
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ hash.calculate(LabelSequence(Name("EXAMPLE"))));
+}
+
+TEST_F(NSEC3HashTest, calculate) {
+ {
+ SCOPED_TRACE("calculate check with NSEC3PARAM based hash");
+ calculateCheck(*test_hash);
+ }
+ {
+ SCOPED_TRACE("calculate check with NSEC3 based hash");
+ calculateCheck(*test_hash_nsec3);
+ }
+ {
+ SCOPED_TRACE("calculate check with args based hash");
+ calculateCheck(*test_hash_args);
+ }
+
+ // Some boundary cases: 0-iteration and empty salt. Borrowed from the
+ // .com zone data.
+ EXPECT_EQ("CK0POJMG874LJREF7EFN8430QVIT8BSM",
+ NSEC3HashPtr(NSEC3Hash::create(generic::NSEC3PARAM("1 0 0 -")))
+ ->calculate(Name("com")));
+ EXPECT_EQ("CK0POJMG874LJREF7EFN8430QVIT8BSM",
+ NSEC3HashPtr(NSEC3Hash::create(generic::NSEC3PARAM("1 0 0 -")))
+ ->calculate(LabelSequence(Name("com"))));
+
+ // Using unusually large iterations, something larger than the 8-bit range.
+ // (expected hash value generated by BIND 9's dnssec-signzone)
+ EXPECT_EQ("COG6A52MJ96MNMV3QUCAGGCO0RHCC2Q3",
+ NSEC3HashPtr(NSEC3Hash::create(
+ generic::NSEC3PARAM("1 0 256 AABBCCDD")))
+ ->calculate(LabelSequence(Name("example.org"))));
+}
+
+// Common checks for match cases
+template <typename RDATAType>
+void
+matchCheck(NSEC3Hash& hash, const string& postfix) {
+ // If all parameters match, it's considered to be matched.
+ EXPECT_TRUE(hash.match(RDATAType("1 0 12 aabbccdd" + postfix)));
+
+ // Algorithm doesn't match
+ EXPECT_FALSE(hash.match(RDATAType("2 0 12 aabbccdd" + postfix)));
+ // Iterations doesn't match
+ EXPECT_FALSE(hash.match(RDATAType("1 0 1 aabbccdd" + postfix)));
+ // Salt doesn't match
+ EXPECT_FALSE(hash.match(RDATAType("1 0 12 aabbccde" + postfix)));
+ // Salt doesn't match: the other has an empty salt
+ EXPECT_FALSE(hash.match(RDATAType("1 0 12 -" + postfix)));
+ // Flags don't matter
+ EXPECT_TRUE(hash.match(RDATAType("1 1 12 aabbccdd" + postfix)));
+}
+
+TEST_F(NSEC3HashTest, matchWithNSEC3) {
+ {
+ SCOPED_TRACE("match NSEC3PARAM based hash against NSEC3 parameters");
+ matchCheck<generic::NSEC3>(*test_hash, " " + string(nsec3_common));
+ }
+ {
+ SCOPED_TRACE("match NSEC3 based hash against NSEC3 parameters");
+ matchCheck<generic::NSEC3>(*test_hash_nsec3,
+ " " + string(nsec3_common));
+ }
+}
+
+TEST_F(NSEC3HashTest, matchWithNSEC3PARAM) {
+ {
+ SCOPED_TRACE("match NSEC3PARAM based hash against NSEC3 parameters");
+ matchCheck<generic::NSEC3PARAM>(*test_hash, "");
+ }
+ {
+ SCOPED_TRACE("match NSEC3 based hash against NSEC3 parameters");
+ matchCheck<generic::NSEC3PARAM>(*test_hash_nsec3, "");
+ }
+}
+
+// A simple faked hash calculator and a dedicated creator for it.
+class TestNSEC3Hash : public NSEC3Hash {
+ virtual string calculate(const Name&) const {
+ return ("00000000000000000000000000000000");
+ }
+ virtual string calculate(const LabelSequence&) const {
+ return ("00000000000000000000000000000000");
+ }
+ virtual bool match(const generic::NSEC3PARAM&) const {
+ return (true);
+ }
+ virtual bool match(const generic::NSEC3&) const {
+ return (true);
+ }
+};
+
+// This faked creator basically creates the faked calculator regardless of
+// the passed NSEC3PARAM or NSEC3. But if the most significant bit of flags
+// is set, it will behave like the default creator.
+class TestNSEC3HashCreator : public NSEC3HashCreator {
+public:
+ virtual NSEC3Hash* create(const generic::NSEC3PARAM& param) const {
+ if ((param.getFlags() & 0x80) != 0) {
+ return (default_creator_.create(param));
+ }
+ return (new TestNSEC3Hash);
+ }
+ virtual NSEC3Hash* create(const generic::NSEC3& nsec3) const {
+ if ((nsec3.getFlags() & 0x80) != 0) {
+ return (default_creator_.create(nsec3));
+ }
+ return (new TestNSEC3Hash);
+ }
+ virtual NSEC3Hash* create(uint8_t, uint16_t,
+ const uint8_t*, size_t) const {
+ isc_throw(isc::Unexpected,
+ "This method is not implemented here.");
+ }
+private:
+ DefaultNSEC3HashCreator default_creator_;
+};
+
+TEST_F(NSEC3HashTest, setCreator) {
+ // Re-check an existing case using the default creator/hash implementation
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ test_hash->calculate(Name("example")));
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ test_hash->calculate(LabelSequence(Name("example"))));
+
+ // Replace the creator, and confirm the hash values are faked
+ TestNSEC3HashCreator test_creator;
+ setNSEC3HashCreator(&test_creator);
+ // Re-create the hash object with the new creator
+ test_hash.reset(NSEC3Hash::create(generic::NSEC3PARAM("1 0 12 aabbccdd")));
+ EXPECT_EQ("00000000000000000000000000000000",
+ test_hash->calculate(Name("example")));
+ EXPECT_EQ("00000000000000000000000000000000",
+ test_hash->calculate(LabelSequence(Name("example"))));
+ // Same for hash from NSEC3 RDATA
+ test_hash.reset(NSEC3Hash::create(generic::NSEC3
+ ("1 0 12 aabbccdd " +
+ string(nsec3_common))));
+ EXPECT_EQ("00000000000000000000000000000000",
+ test_hash->calculate(Name("example")));
+ EXPECT_EQ("00000000000000000000000000000000",
+ test_hash->calculate(LabelSequence(Name("example"))));
+
+ // If we set a special flag big (0x80) on creation, it will act like the
+ // default creator.
+ test_hash.reset(NSEC3Hash::create(generic::NSEC3PARAM(
+ "1 128 12 aabbccdd")));
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ test_hash->calculate(Name("example")));
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ test_hash->calculate(LabelSequence(Name("example"))));
+ test_hash.reset(NSEC3Hash::create(generic::NSEC3
+ ("1 128 12 aabbccdd " +
+ string(nsec3_common))));
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ test_hash->calculate(Name("example")));
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ test_hash->calculate(LabelSequence(Name("example"))));
+
+ // Reset the creator to default, and confirm that
+ setNSEC3HashCreator(NULL);
+ test_hash.reset(NSEC3Hash::create(generic::NSEC3PARAM("1 0 12 aabbccdd")));
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ test_hash->calculate(Name("example")));
+ EXPECT_EQ("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+ test_hash->calculate(LabelSequence(Name("example"))));
+}
+
+} // end namespace