Browse Source

Merge base32, sha1, and NSEC3/NSEC3PARAM rdata implementations to trunk
(Note: I expect sha1 to be replaced, and to add more test cases to all
of the unit tests.)


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1125 e5f2f494-b856-4b98-b285-d166d9295462

Evan Hunt 15 years ago
parent
commit
5fd4500eb8

+ 2 - 0
src/lib/dns/Makefile.am

@@ -18,7 +18,9 @@ libdns_la_SOURCES += rrset.h rrset.cc
 libdns_la_SOURCES += rrsetlist.h rrsetlist.cc
 libdns_la_SOURCES += question.h question.cc
 libdns_la_SOURCES += message.h message.cc
+libdns_la_SOURCES += base32.h base32.cc
 libdns_la_SOURCES += base64.h base64.cc
+libdns_la_SOURCES += sha1.h sha1.cc
 libdns_la_SOURCES += tsig.h tsig.cc
 libdns_la_SOURCES += dnstime.h dnstime.cc
 libdns_la_SOURCES += hex.h hex.cc

+ 198 - 0
src/lib/dns/base32.cc

@@ -0,0 +1,198 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <cassert>
+#include <iterator>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+
+#include <exceptions/exceptions.h>
+#include <boost/foreach.hpp>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "base32.h"
+
+using namespace std;
+
+namespace isc {
+namespace dns {
+
+static const char base32hex[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+
+string
+encodeBase32(const vector<uint8_t>& binary)
+{
+    ostringstream base32;
+    size_t len = binary.size();
+    size_t pos = 0;
+    while (len > 0) {
+        char buf[9];
+        memset(buf, '=', 8);
+        buf[8] = '\0';
+
+        uint8_t digit = (binary.at(pos) >> 3) & 0x1f;
+        buf[0] = base32hex[digit];
+
+        if (len == 1) {
+            digit = (binary.at(pos) << 2) & 0x1c;
+            buf[1] = base32hex[digit];
+            base32 << buf;
+            break;
+        }
+
+        digit = ((binary.at(pos) << 2) & 0x1c) |
+                ((binary.at(pos + 1) >> 6) & 0x03);
+        buf[1] = base32hex[digit];
+
+        digit = (binary.at(pos + 1) >> 1) & 0x1f;
+        buf[2] = base32hex[digit];
+
+        if (len == 2) {
+            digit = (binary.at(pos + 1) << 4) & 0x10;
+            buf[3] = base32hex[digit];
+            base32 << buf;
+            break;
+        }
+
+        digit = ((binary.at(pos + 1) << 4) & 0x10) |
+                ((binary.at(pos + 2) >> 4) & 0x0f);
+        buf[3] = base32hex[digit];
+        if (len == 3) {
+            digit = (binary.at(pos + 2) << 1) & 0x1e;
+            buf[4] = base32hex[digit];
+            base32 << buf;
+            break;
+        }
+
+        digit = ((binary.at(pos + 2) << 1) & 0x1e) |
+                ((binary.at(pos + 3) >> 7) & 0x01);
+        buf[4] = base32hex[digit];
+
+        digit = (binary.at(pos + 3) >> 2) & 0x1f;
+        buf[5] = base32hex[digit];
+
+        if (len == 4) {
+            digit = (binary.at(pos + 3) << 3) & 0x18;
+            buf[6] = base32hex[digit];
+            base32 << buf;
+            break;
+        }
+
+        digit = ((binary.at(pos + 3) << 3) & 0x18) |
+                ((binary.at(pos + 4) >> 5) & 0x07);
+        buf[6] = base32hex[digit];
+
+        digit = binary.at(pos + 4) & 0x1f;
+        buf[7] = base32hex[digit];
+
+        len -= 5;
+        pos += 5;
+
+        base32 << buf;
+    }
+
+    return (base32.str());
+}
+
+void
+decodeBase32(const string& base32, vector<uint8_t>& result)
+{
+    ostringstream comp;
+
+    // compress input by removing whitespace
+    size_t len = base32.length();
+    for (int i = 0; i < len; i++) {
+        char c = base32.at(i);
+        if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+            continue;
+        }
+        comp << c;
+    }
+
+    // base32 text should be a multiple of 8 bytes long
+    if (comp.str().length() % 8 != 0) {
+        dns_throw (BadBase32String, "Invalid length");
+    }
+
+    istringstream iss(comp.str());
+    result.clear();
+    bool seenpad = false;
+    while (!iss.eof()) {
+        string group;
+
+        iss >> setw(8) >> group;
+        if (iss.bad() || iss.fail()) {
+            dns_throw (BadBase32String, "Could not parse base32 input");
+        }
+
+        uint8_t octet = 0;
+        for (int i = 0; i < 8; i ++) {
+            char c = toupper(group.at(i));
+            int value;
+
+            if (c != '=' && seenpad) {
+                dns_throw (BadBase32String, "Invalid base32 input");
+            } else 
+
+            if (c == '=' && !seenpad) {
+                value = 0;
+                seenpad = true;
+            } else {
+                const char* pos = strchr(base32hex, c);
+                if (!pos) {
+                    dns_throw (BadBase32String, "Invalid base32 input");
+                }
+                value = pos - base32hex;
+                assert (value < 32);
+            }
+
+            switch (i) {
+            case 0: octet |= value << 3;
+                    break;
+            case 1: octet |= value >> 2;
+                    result.push_back(octet);
+                    octet = (value & 0x03) << 6;
+                    break;
+            case 2: octet |= value << 1;
+                    break;
+            case 3: octet |= value >> 4;
+                    result.push_back(octet);
+                    octet = (value & 0x0f) << 4;
+                    break;
+            case 4: octet |= value >> 1;
+                    result.push_back(octet);
+                    octet = (value & 0x01) << 7;
+                    break;
+            case 5: octet |= value << 2;
+                    break;
+            case 6: octet |= value >> 3;
+                    result.push_back(octet);
+                    octet = (value & 0x07) << 5;
+                    break;
+            case 7: octet |= value;
+                    result.push_back(octet);
+            }
+        }
+    }
+}
+
+}
+}

+ 54 - 0
src/lib/dns/base32.h

@@ -0,0 +1,54 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __BASE32_H
+#define __BASE32_H 1
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include <exceptions/exceptions.h>
+
+//
+// Note: this helper module isn't specific to the DNS protocol per se.
+// We should probably move this to somewhere else, possibly in some common
+// utility area.
+//
+
+namespace isc {
+namespace dns {
+
+///
+/// \brief A standard DNS (or ISC) module exception that is thrown if a
+/// base32 decoder encounters an invalid input.
+///
+class BadBase32String : public Exception {
+public:
+    BadBase32String(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+std::string encodeBase32(const std::vector<uint8_t>& binary);
+void decodeBase32(const std::string& hex, std::vector<uint8_t>& result);
+}
+}
+
+#endif  // __BASE32_H
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 1 - 1
src/lib/dns/gen-rdatacode.py.in

@@ -26,7 +26,7 @@ from os.path import getmtime
 import re
 import sys
 
-re_typecode = re.compile('([a-z]+)_(\d+)')
+re_typecode = re.compile('([\da-z]+)_(\d+)')
 classcode2txt = {}
 typecode2txt = {}
 typeandclass = []

+ 325 - 0
src/lib/dns/rdata/generic/nsec3_50.cc

@@ -0,0 +1,325 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include "base32.h"
+#include "buffer.h"
+#include "hex.h"
+#include "messagerenderer.h"
+#include "name.h"
+#include "rrtype.h"
+#include "rrttl.h"
+#include "rdata.h"
+#include "rdataclass.h"
+#include <boost/lexical_cast.hpp>
+
+#include <stdio.h>
+#include <time.h>
+
+using namespace std;
+
+// BEGIN_ISC_NAMESPACE
+// BEGIN_RDATA_NAMESPACE
+
+struct NSEC3Impl {
+    // straightforward representation of NSEC3 RDATA fields
+    NSEC3Impl(uint8_t hash, uint8_t flags, uint16_t iterations,
+              vector<uint8_t>salt, vector<uint8_t>next,
+              vector<uint8_t> typebits) :
+        hash_(hash), flags_(flags), iterations_(iterations),
+        salt_(salt), next_(next), typebits_(typebits)
+    {}
+
+    uint8_t hash_;
+    uint8_t flags_;
+    uint16_t iterations_;
+    vector<uint8_t> salt_;
+    vector<uint8_t> next_;
+    vector<uint8_t> typebits_;
+};
+
+NSEC3::NSEC3(const string& nsec3_str) :
+    impl_(NULL)
+{
+    istringstream iss(nsec3_str);
+    unsigned int hash, flags, iterations;
+    string salthex;
+
+    iss >> hash >> flags >> iterations >> salthex;
+    if (iss.bad() || iss.fail()) {
+        dns_throw(InvalidRdataText, "Invalid NSEC3 text");
+    }
+    if (hash > 0xf) {
+        dns_throw(InvalidRdataText, "NSEC3 hash out of range");
+    }
+    if (flags > 0xff) {
+        dns_throw(InvalidRdataText, "NSEC3 flags out of range");
+    }
+    if (iterations > 0xffff) {
+        dns_throw(InvalidRdataText, "NSEC3 iterations out of range");
+    }
+
+    vector<uint8_t> salt;
+    decodeHex(salthex, salt);
+
+    string nextstr;
+    iss >> setw(32) >> nextstr;
+    vector<uint8_t> next;
+    if (iss.bad() || iss.fail()) {
+        dns_throw(InvalidRdataText, "Invalid NSEC3 hash");
+    }
+    decodeBase32(nextstr, next);
+
+    uint8_t bitmap[8 * 1024];       // 64k bits
+    vector<uint8_t> typebits;
+
+    memset(bitmap, 0, sizeof(bitmap));
+    do { 
+        string type;
+        int code;
+        iss >> type;
+        code = RRType(type).getCode();
+        bitmap[code / 8] |= (0x80 >> (code % 8));
+    } while(!iss.eof());
+
+    for (int window = 0; window < 256; window++) {
+        int octet;
+        for (octet = 31; octet >= 0; octet--) {
+            if (bitmap[window * 32 + octet] != 0) {
+                break;
+            }
+        }
+        if (octet < 0)
+            continue;
+        typebits.push_back(window);
+        typebits.push_back(octet + 1);
+        for (int i = 0; i <= octet; i++) {
+            typebits.push_back(bitmap[window * 32 + i]);
+        }
+    }
+
+    impl_ = new NSEC3Impl(hash, flags, iterations, salt, next, typebits);
+}
+
+NSEC3::NSEC3(InputBuffer& buffer, size_t rdata_len)
+{
+    if (rdata_len < 5) {
+        dns_throw(InvalidRdataLength, "NSEC3 too short");
+    }
+
+    uint8_t hash = buffer.readUint8();
+    uint8_t flags = buffer.readUint8();
+    uint16_t iterations = buffer.readUint16();
+    rdata_len -= 4;
+
+    uint8_t saltlen = buffer.readUint8();
+    --rdata_len;
+
+    if (rdata_len < saltlen) {
+        dns_throw(InvalidRdataLength, "NSEC3 salt too short");
+    }
+
+    vector<uint8_t> salt(saltlen);
+    buffer.readData(&salt[0], saltlen);
+    rdata_len -= saltlen;
+
+    uint8_t nextlen = buffer.readUint8();
+    --rdata_len;
+
+    if (rdata_len < nextlen) {
+        dns_throw(InvalidRdataLength, "NSEC3 next hash too short");
+    }
+
+    vector<uint8_t> next(nextlen);
+    buffer.readData(&next[0], nextlen);
+    rdata_len -= nextlen;
+
+    if (rdata_len == 0) {
+        dns_throw(InvalidRdataLength, "NSEC3 type bitmap too short");
+    }
+
+    // FIXIT: we cannot naively copy the data because the bitmaps have
+    // semantics and other part of this class assumes they are valid.
+    vector<uint8_t> typebits(rdata_len);
+    buffer.readData(&typebits[0], rdata_len);
+
+    impl_ = new NSEC3Impl(hash, flags, iterations, salt, next, typebits);
+}
+
+NSEC3::NSEC3(const NSEC3& source) :
+    impl_(new NSEC3Impl(*source.impl_))
+{}
+
+NSEC3&
+NSEC3::operator=(const NSEC3& source)
+{
+    if (impl_ == source.impl_) {
+        return (*this);
+    }
+
+    NSEC3Impl* newimpl = new NSEC3Impl(*source.impl_);
+    delete impl_;
+    impl_ = newimpl;
+
+    return (*this);
+}
+
+NSEC3::~NSEC3()
+{
+    delete impl_;
+}
+
+string
+NSEC3::toText() const
+{
+    ostringstream s;
+    int len = 0;
+    for (int i = 0; i < impl_->typebits_.size(); i += len) {
+        assert(i + 2 <= impl_->typebits_.size());
+        int window = impl_->typebits_[i];
+        len = impl_->typebits_[i + 1];
+        assert(len >= 0 && len < 32);
+        i += 2;
+        for (int j = 0; j < len; j++) {
+            if (impl_->typebits_[i + j] == 0) {
+                continue;
+            }
+            for (int k = 0; k < 8; k++) {
+                if ((impl_->typebits_[i + j] & (0x80 >> k)) == 0) {
+                    continue;
+                }
+                int t = window * 256 + j * 8 + k;
+                s << " " << RRType(t).toText();
+            }
+        }
+    }
+
+    using namespace boost;
+    return (lexical_cast<string>(static_cast<int>(impl_->hash_)) +
+        " " + lexical_cast<string>(static_cast<int>(impl_->flags_)) +
+        " " + lexical_cast<string>(static_cast<int>(impl_->iterations_)) +
+        " " + encodeHex(impl_->salt_) +
+        " " + encodeBase32(impl_->next_) + s.str());
+}
+
+void
+NSEC3::toWire(OutputBuffer& buffer) const
+{
+    buffer.writeUint8(impl_->hash_);
+    buffer.writeUint8(impl_->flags_);
+    buffer.writeUint16(impl_->iterations_);
+    buffer.writeUint8(impl_->salt_.size());
+    buffer.writeData(&impl_->salt_[0], impl_->salt_.size());
+    buffer.writeUint8(impl_->next_.size());
+    buffer.writeData(&impl_->next_[0], impl_->next_.size());
+    buffer.writeData(&impl_->typebits_[0], impl_->typebits_.size());
+}
+
+void
+NSEC3::toWire(MessageRenderer& renderer) const
+{
+    renderer.writeUint8(impl_->hash_);
+    renderer.writeUint8(impl_->flags_);
+    renderer.writeUint16(impl_->iterations_);
+    renderer.writeUint8(impl_->salt_.size());
+    renderer.writeData(&impl_->salt_[0], impl_->salt_.size());
+    renderer.writeUint8(impl_->next_.size());
+    renderer.writeData(&impl_->next_[0], impl_->next_.size());
+    renderer.writeData(&impl_->typebits_[0], impl_->typebits_.size());
+}
+
+int
+NSEC3::compare(const Rdata& other) const
+{
+    const NSEC3& other_nsec3 = dynamic_cast<const NSEC3&>(other);
+
+    if (impl_->hash_ != other_nsec3.impl_->hash_) {
+        return (impl_->hash_ < other_nsec3.impl_->hash_ ? -1 : 1);
+    }
+    if (impl_->flags_ != other_nsec3.impl_->flags_) {
+        return (impl_->flags_ < other_nsec3.impl_->flags_ ? -1 : 1);
+    }
+    if (impl_->iterations_ != other_nsec3.impl_->iterations_) {
+        return (impl_->iterations_ < other_nsec3.impl_->iterations_ ? -1 : 1);
+    }
+
+    size_t this_len = impl_->salt_.size();
+    size_t other_len = other_nsec3.impl_->salt_.size();
+    size_t cmplen = min(this_len, other_len);
+    int cmp = memcmp(&impl_->salt_[0], &other_nsec3.impl_->salt_[0], cmplen);
+    if (cmp != 0) {
+        return (cmp);
+    } else if (this_len < other_len) {
+        return (-1);
+    } else if (this_len > other_len) {
+        return (1);
+    }
+
+    this_len = impl_->salt_.size();
+    other_len = other_nsec3.impl_->salt_.size();
+    cmplen = min(this_len, other_len);
+    cmp = memcmp(&impl_->next_[0], &other_nsec3.impl_->next_[0], cmplen);
+    if (cmp != 0) {
+        return (cmp);
+    } else if (this_len < other_len) {
+        return (-1);
+    } else if (this_len > other_len) {
+        return (1);
+    }
+
+    this_len = impl_->typebits_.size();
+    other_len = other_nsec3.impl_->typebits_.size();
+    cmplen = min(this_len, other_len);
+    cmp = memcmp(&impl_->typebits_[0], &other_nsec3.impl_->typebits_[0],
+                 cmplen);
+    if (cmp != 0) {
+        return (cmp);
+    } else if (this_len < other_len) {
+        return (-1);
+    } else if (this_len > other_len) {
+        return (1);
+    } else {
+        return (0);
+    }
+}
+
+uint8_t
+NSEC3::getHash() const {
+    return impl_->hash_;
+}
+
+uint8_t
+NSEC3::getFlags() const {
+    return impl_->flags_;
+}
+
+uint16_t
+NSEC3::getIterations() const {
+    return impl_->iterations_;
+}
+
+vector<uint8_t>
+NSEC3::getSalt() const {
+    return impl_->salt_;
+}
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE

+ 60 - 0
src/lib/dns/rdata/generic/nsec3_50.h

@@ -0,0 +1,60 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id: nsec_47.h 991 2010-02-26 08:53:26Z jinmei $
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "name.h"
+#include "rrtype.h"
+#include "rrttl.h"
+#include "rdata.h"
+
+// BEGIN_HEADER_GUARD
+
+// BEGIN_ISC_NAMESPACE
+
+// BEGIN_COMMON_DECLARATIONS
+// END_COMMON_DECLARATIONS
+
+// BEGIN_RDATA_NAMESPACE
+
+struct NSEC3Impl;
+
+class NSEC3 : public Rdata {
+public:
+    // BEGIN_COMMON_MEMBERS
+    // END_COMMON_MEMBERS
+    NSEC3& operator=(const NSEC3& source);
+    ~NSEC3();
+
+    uint8_t getHash() const;
+    uint8_t getFlags() const;
+    uint16_t getIterations() const;
+    std::vector<uint8_t> getSalt() const;
+
+private:
+    NSEC3Impl* impl_;
+};
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
+// END_HEADER_GUARD
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 200 - 0
src/lib/dns/rdata/generic/nsec3param_51.cc

@@ -0,0 +1,200 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include "buffer.h"
+#include "hex.h"
+#include "messagerenderer.h"
+#include "name.h"
+#include "rdata.h"
+#include "rdataclass.h"
+#include <boost/lexical_cast.hpp>
+
+#include <stdio.h>
+#include <time.h>
+
+using namespace std;
+
+// BEGIN_ISC_NAMESPACE
+// BEGIN_RDATA_NAMESPACE
+
+struct NSEC3PARAMImpl {
+    // straightforward representation of NSEC3PARAM RDATA fields
+    NSEC3PARAMImpl(uint8_t hash, uint8_t flags, uint16_t iterations,
+                   vector<uint8_t>salt) :
+        hash_(hash), flags_(flags), iterations_(iterations), salt_(salt)
+    {}
+
+    uint8_t hash_;
+    uint8_t flags_;
+    uint16_t iterations_;
+    const vector<uint8_t> salt_;
+};
+
+NSEC3PARAM::NSEC3PARAM(const string& nsec3param_str) :
+    impl_(NULL)
+{
+    istringstream iss(nsec3param_str);
+    uint16_t hash, flags, iterations;
+    stringbuf saltbuf;
+
+    iss >> hash >> flags >> iterations >> &saltbuf;
+    if (iss.bad() || iss.fail()) {
+        dns_throw(InvalidRdataText, "Invalid NSEC3PARAM text");
+    }
+    if (hash > 0xf) {
+        dns_throw(InvalidRdataText, "NSEC3PARAM hash out of range");
+    }
+    if (flags > 0xff) {
+        dns_throw(InvalidRdataText, "NSEC3PARAM flags out of range");
+    }
+
+    vector<uint8_t> salt;
+    decodeHex(saltbuf.str(), salt);
+
+    impl_ = new NSEC3PARAMImpl(hash, flags, iterations, salt);
+}
+
+NSEC3PARAM::NSEC3PARAM(InputBuffer& buffer, size_t rdata_len)
+{
+    if (rdata_len < 4) {
+        dns_throw(InvalidRdataLength, "NSEC3PARAM too short");
+    }
+
+    uint8_t hash = buffer.readUint8();
+    uint8_t flags = buffer.readUint8();
+    uint16_t iterations = buffer.readUint16();
+    rdata_len -= 4;
+
+    uint8_t saltlen = buffer.readUint8();
+    --rdata_len;
+
+    if (rdata_len < saltlen) {
+        dns_throw(InvalidRdataLength, "NSEC3PARAM salt too short");
+    }
+
+    vector<uint8_t> salt(saltlen);
+    buffer.readData(&salt[0], saltlen);
+
+    impl_ = new NSEC3PARAMImpl(hash, flags, iterations, salt);
+}
+
+NSEC3PARAM::NSEC3PARAM(const NSEC3PARAM& source) :
+    impl_(new NSEC3PARAMImpl(*source.impl_))
+{}
+
+NSEC3PARAM&
+NSEC3PARAM::operator=(const NSEC3PARAM& source)
+{
+    if (impl_ == source.impl_) {
+        return (*this);
+    }
+
+    NSEC3PARAMImpl* newimpl = new NSEC3PARAMImpl(*source.impl_);
+    delete impl_;
+    impl_ = newimpl;
+
+    return (*this);
+}
+
+NSEC3PARAM::~NSEC3PARAM()
+{
+    delete impl_;
+}
+
+string
+NSEC3PARAM::toText() const
+{
+    using namespace boost;
+    return (lexical_cast<string>(static_cast<int>(impl_->hash_)) +
+        " " + lexical_cast<string>(static_cast<int>(impl_->flags_)) +
+        " " + lexical_cast<string>(static_cast<int>(impl_->iterations_)) +
+        " " + encodeHex(impl_->salt_));
+}
+
+void
+NSEC3PARAM::toWire(OutputBuffer& buffer) const
+{
+    buffer.writeUint8(impl_->hash_);
+    buffer.writeUint8(impl_->flags_);
+    buffer.writeUint16(impl_->iterations_);
+    buffer.writeUint8(impl_->salt_.size());
+    buffer.writeData(&impl_->salt_[0], impl_->salt_.size());
+}
+
+void
+NSEC3PARAM::toWire(MessageRenderer& renderer) const
+{
+    renderer.writeUint8(impl_->hash_);
+    renderer.writeUint8(impl_->flags_);
+    renderer.writeUint16(impl_->iterations_);
+    renderer.writeUint8(impl_->salt_.size());
+    renderer.writeData(&impl_->salt_[0], impl_->salt_.size());
+}
+
+int
+NSEC3PARAM::compare(const Rdata& other) const
+{
+    const NSEC3PARAM& other_param = dynamic_cast<const NSEC3PARAM&>(other);
+
+    if (impl_->hash_ != other_param.impl_->hash_) {
+        return (impl_->hash_ < other_param.impl_->hash_ ? -1 : 1);
+    }
+    if (impl_->flags_ != other_param.impl_->flags_) {
+        return (impl_->flags_ < other_param.impl_->flags_ ? -1 : 1);
+    }
+    if (impl_->iterations_ != other_param.impl_->iterations_) {
+        return (impl_->iterations_ < other_param.impl_->iterations_ ? -1 : 1);
+    }
+
+    size_t this_len = impl_->salt_.size();
+    size_t other_len = other_param.impl_->salt_.size();
+    size_t cmplen = min(this_len, other_len);
+    int cmp = memcmp(&impl_->salt_[0], &other_param.impl_->salt_[0],
+                     cmplen);
+    if (cmp != 0) {
+        return (cmp);
+    } else {
+        return ((this_len == other_len) ? 0 : (this_len < other_len) ? -1 : 1);
+    }
+}
+
+uint8_t
+NSEC3PARAM::getHash() const {
+    return impl_->hash_;
+}
+
+uint8_t
+NSEC3PARAM::getFlags() const {
+    return impl_->flags_;
+}
+
+uint16_t
+NSEC3PARAM::getIterations() const {
+    return impl_->iterations_;
+}
+
+vector<uint8_t>
+NSEC3PARAM::getSalt() const {
+    return impl_->salt_;
+}
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE

+ 62 - 0
src/lib/dns/rdata/generic/nsec3param_51.h

@@ -0,0 +1,62 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "name.h"
+#include "rrtype.h"
+#include "rrttl.h"
+#include "rdata.h"
+
+// BEGIN_HEADER_GUARD
+
+// BEGIN_ISC_NAMESPACE
+
+// BEGIN_COMMON_DECLARATIONS
+// END_COMMON_DECLARATIONS
+
+// BEGIN_RDATA_NAMESPACE
+
+struct NSEC3PARAMImpl;
+
+class NSEC3PARAM : public Rdata {
+public:
+    // BEGIN_COMMON_MEMBERS
+    // END_COMMON_MEMBERS
+    NSEC3PARAM& operator=(const NSEC3PARAM& source);
+    ~NSEC3PARAM();
+
+    ///
+    /// Specialized methods
+    ///
+    uint8_t getHash() const;
+    uint8_t getFlags() const;
+    uint16_t getIterations() const;
+    std::vector<uint8_t> getSalt() const;
+private:
+    NSEC3PARAMImpl* impl_;
+};
+
+// END_RDATA_NAMESPACE
+// END_ISC_NAMESPACE
+// END_HEADER_GUARD
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 356 - 0
src/lib/dns/sha1.cc

@@ -0,0 +1,356 @@
+/*
+ *  sha1.c
+ *  Adapted from RFC 3174, "US Secure Hash Algorithm 1", D. Eastlake et al
+ *
+ *  Description:
+ *      This file implements the Secure Hashing Algorithm 1 as
+ *      defined in FIPS PUB 180-1 published April 17, 1995.
+ *
+ *      The SHA-1, produces a 160-bit message digest for a given
+ *      data stream.  It should take about 2**n steps to find a
+ *      message with the same digest as a given message and
+ *      2**(n/2) to find any two messages with the same digest,
+ *      when n is the digest size in bits.  Therefore, this
+ *      algorithm can serve as a means of providing a
+ *      "fingerprint" for a message.
+ *
+ *  Portability Issues:
+ *      SHA-1 is defined in terms of 32-bit "words".  This code
+ *      uses <stdint.h> (included via "sha1.h" to define 32 and 8
+ *      bit unsigned integer types.  If your C compiler does not
+ *      support 32 bit unsigned integers, this code is not
+ *      appropriate.
+ *
+ *  Caveats:
+ *      SHA-1 is designed to work with messages less than 2^64 bits
+ *      long.  Although SHA-1 allows a message digest to be generated
+ *      for messages of any number of bits less than 2^64, this
+ *      implementation only works with messages with a length that is
+ *      a multiple of the size of an 8-bit character.
+ */
+
+#include "sha1.h"
+
+/* Local Function Prototyptes */
+static void SHA1PadMessage(SHA1Context *);
+static void SHA1ProcessMessageBlock(SHA1Context *);
+
+/*
+ *  SHA1Reset
+ *
+ *  Description:
+ *      This function will initialize the SHA1Context in preparation
+ *      for computing a new SHA1 message digest.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to reset.
+ *
+ *  Returns:
+ *      sha Error Code.
+ *
+ */
+int
+SHA1Reset(SHA1Context *context) {
+    if (!context) {
+        return (SHA_NULL);
+    }
+
+    context->Length_Low             = 0;
+    context->Length_High            = 0;
+    context->Message_Block_Index    = 0;
+
+    context->Intermediate_Hash[0]   = 0x67452301;
+    context->Intermediate_Hash[1]   = 0xEFCDAB89;
+    context->Intermediate_Hash[2]   = 0x98BADCFE;
+    context->Intermediate_Hash[3]   = 0x10325476;
+    context->Intermediate_Hash[4]   = 0xC3D2E1F0;
+
+    context->Computed   = 0;
+    context->Corrupted  = 0;
+    return (SHA_SUCCESS);
+}
+
+/*
+ *  SHA1Result
+ *
+ *  Description:
+ *      This function will return the 160-bit message digest into the
+ *      Message_Digest array  provided by the caller.
+ *      NOTE: The first octet of hash is stored in the 0th element,
+ *            the last octet of hash in the 19th element.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to use to calculate the SHA-1 hash.
+ *      Message_Digest: [out]
+ *          Where the digest is returned.
+ *
+ *  Returns:
+ *      sha Error Code.
+ *
+ */
+int
+SHA1Result(SHA1Context *context, uint8_t Message_Digest[SHA1_HASHSIZE]) {
+    int i;
+
+    if (!context || !Message_Digest) {
+        return (SHA_NULL);
+    }
+
+    if (context->Corrupted) {
+        return (context->Corrupted);
+    }
+
+    if (!context->Computed) {
+        SHA1PadMessage(context);
+        for(i = 0; i < 64; ++i) {
+            /* message may be sensitive, clear it out */
+            context->Message_Block[i] = 0;
+        }
+        context->Length_Low = 0;    /* and clear length */
+        context->Length_High = 0;
+        context->Computed = 1;
+    }
+
+    for(i = 0; i < SHA1_HASHSIZE; ++i) {
+        Message_Digest[i] = context->Intermediate_Hash[i>>2]
+                            >> 8 * (3 - (i & 0x03));
+    }
+
+    return (SHA_SUCCESS);
+}
+
+/*
+ *  SHA1Input
+ *
+ *  Description:
+ *      This function accepts an array of octets as the next portion
+ *      of the message.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The SHA context to update
+ *      message_array: [in]
+ *          An array of characters representing the next portion of
+ *          the message.
+ *      length: [in]
+ *          The length of the message in message_array
+ *
+ *  Returns:
+ *      sha Error Code.
+ *
+ */
+int
+SHA1Input(SHA1Context *context, const uint8_t *message_array, unsigned length) {
+    if (!length) {
+        return (SHA_SUCCESS);
+    }
+
+    if (!context || !message_array) {
+        return (SHA_NULL);
+    }
+
+    if (context->Computed) {
+        context->Corrupted = SHA_STATEERROR;
+        return (SHA_STATEERROR);
+    }
+
+    if (context->Corrupted) {
+         return (context->Corrupted);
+    }
+
+    while(length-- && !context->Corrupted) {
+        context->Message_Block[context->Message_Block_Index++] =
+                        (*message_array & 0xFF);
+
+        context->Length_Low += 8;
+        if (context->Length_Low == 0) {
+            context->Length_High++;
+            if (context->Length_High == 0) {
+                /* Message is too long */
+                context->Corrupted = 1;
+            }
+        }
+
+        if (context->Message_Block_Index == 64) {
+            SHA1ProcessMessageBlock(context);
+        }
+
+        message_array++;
+    }
+
+    return (SHA_SUCCESS);
+}
+
+/*
+ *  Define the SHA1 circular left shift
+ */
+static inline int 
+SHA1CircularShift(uint8_t bits, uint32_t word) {
+    return ((word << bits) | (word >> (32 - bits)));
+}
+
+/*
+ *  SHA1ProcessMessageBlock
+ *
+ *  Description:
+ *      This function will process the next 512 bits of the message
+ *      stored in the Message_Block array.
+ *
+ *  Parameters:
+ *      None.
+ *
+ *  Returns:
+ *      Nothing.
+ *
+ *  Comments:
+ *      Many of the variable names in this code, especially the
+ *      single character names, were used because those were the
+ *      names used in the publication.
+ *
+ *
+ */
+static void
+SHA1ProcessMessageBlock(SHA1Context *context) {
+    const uint32_t K[] = {          /* Constants defined in SHA-1   */
+        0x5A827999,
+        0x6ED9EBA1,
+        0x8F1BBCDC,
+        0xCA62C1D6
+    };
+    int           t;                 /* Loop counter                */
+    uint32_t      temp;              /* Temporary word value        */
+    uint32_t      W[80];             /* Word sequence               */
+    uint32_t      A, B, C, D, E;     /* Word buffers                */
+
+    /*
+     *  Initialize the first 16 words in the array W
+     */
+    for(t = 0; t < 16; t++) {
+        W[t] = context->Message_Block[t * 4] << 24;
+        W[t] |= context->Message_Block[t * 4 + 1] << 16;
+        W[t] |= context->Message_Block[t * 4 + 2] << 8;
+        W[t] |= context->Message_Block[t * 4 + 3];
+    }
+
+    for(t = 16; t < 80; t++) {
+       W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+    }
+
+    A = context->Intermediate_Hash[0];
+    B = context->Intermediate_Hash[1];
+    C = context->Intermediate_Hash[2];
+    D = context->Intermediate_Hash[3];
+    E = context->Intermediate_Hash[4];
+
+    for(t = 0; t < 20; t++) {
+        temp =  SHA1CircularShift(5,A) +
+                ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for(t = 20; t < 40; t++) {
+        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for(t = 40; t < 60; t++) {
+        temp = SHA1CircularShift(5,A) +
+               ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    for(t = 60; t < 80; t++) {
+        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+        E = D;
+        D = C;
+        C = SHA1CircularShift(30,B);
+        B = A;
+        A = temp;
+    }
+
+    context->Intermediate_Hash[0] += A;
+    context->Intermediate_Hash[1] += B;
+    context->Intermediate_Hash[2] += C;
+    context->Intermediate_Hash[3] += D;
+    context->Intermediate_Hash[4] += E;
+
+    context->Message_Block_Index = 0;
+}
+
+/*
+ *  SHA1PadMessage
+ *
+ *  Description:
+ *      According to the standard, the message must be padded to an even
+ *      512 bits.  The first padding bit must be a '1'.  The last 64
+ *      bits represent the length of the original message.  All bits in
+ *      between should be 0.  This function will pad the message
+ *      according to those rules by filling the Message_Block array
+ *      accordingly.  It will also call the ProcessMessageBlock function
+ *      provided appropriately.  When it returns, it can be assumed that
+ *      the message digest has been computed.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to pad
+ *      ProcessMessageBlock: [in]
+ *          The appropriate SHA*ProcessMessageBlock function
+ *  Returns:
+ *      Nothing.
+ *
+ */
+
+static void
+SHA1PadMessage(SHA1Context *context) {
+    /*
+     *  Check to see if the current message block is too small to hold
+     *  the initial padding bits and length.  If so, we will pad the
+     *  block, process it, and then continue padding into a second
+     *  block.
+     */
+    if (context->Message_Block_Index > 55) {
+        context->Message_Block[context->Message_Block_Index++] = 0x80;
+        while(context->Message_Block_Index < 64) {
+            context->Message_Block[context->Message_Block_Index++] = 0;
+        }
+
+        SHA1ProcessMessageBlock(context);
+
+        while(context->Message_Block_Index < 56) {
+            context->Message_Block[context->Message_Block_Index++] = 0;
+        }
+    } else {
+        context->Message_Block[context->Message_Block_Index++] = 0x80;
+        while(context->Message_Block_Index < 56) {
+            context->Message_Block[context->Message_Block_Index++] = 0;
+        }
+    }
+
+    /*
+     *  Store the message length as the last 8 octets
+     */
+    context->Message_Block[56] = context->Length_High >> 24;
+    context->Message_Block[57] = context->Length_High >> 16;
+    context->Message_Block[58] = context->Length_High >> 8;
+    context->Message_Block[59] = context->Length_High;
+    context->Message_Block[60] = context->Length_Low >> 24;
+    context->Message_Block[61] = context->Length_Low >> 16;
+    context->Message_Block[62] = context->Length_Low >> 8;
+    context->Message_Block[63] = context->Length_Low;
+
+    SHA1ProcessMessageBlock(context);
+}

+ 63 - 0
src/lib/dns/sha1.h

@@ -0,0 +1,63 @@
+/*
+ *  sha1.h
+ *
+ *  Description:
+ *      This is the header file for code which implements the Secure
+ *      Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
+ *      April 17, 1995.
+ *
+ *      Many of the variable names in this code, especially the
+ *      single character names, were used because those were the names
+ *      used in the publication.
+ *
+ *      Please read the file sha1.c for more information.
+ *
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+#include <stdint.h>
+/*
+ * If you do not have the ISO standard stdint.h header file, then you
+ * must typdef the following:
+ *    name              meaning
+ *  uint32_t         unsigned 32 bit integer
+ *  uint8_t          unsigned 8 bit integer (i.e., unsigned char)
+ *  int_least16_t    integer of >= 16 bits
+ *
+ */
+
+enum {
+    SHA_SUCCESS = 0,
+    SHA_NULL,            /* Null pointer parameter */
+    SHA_STATEERROR       /* called Input after Result */
+};
+
+enum {
+    SHA1_HASHSIZE = 20
+};
+
+/*
+ *  This structure will hold context information for the SHA-1
+ *  hashing operation
+ */
+typedef struct SHA1Context
+{
+    uint32_t Intermediate_Hash[SHA1_HASHSIZE/4]; /* Message Digest */
+    uint32_t Length_Low;                /* Message length in bits */
+    uint32_t Length_High;               /* Message length in bits */
+    int_least16_t Message_Block_Index;  /* Index into message block array */
+    uint8_t Message_Block[64];          /* 512-bit message blocks */
+    int Computed;                       /* Is the digest computed? */
+    int Corrupted;                      /* Is the message digest corrupted? */
+} SHA1Context;
+
+/*
+ *  Function Prototypes
+ */
+int SHA1Reset(SHA1Context *);
+int SHA1Input(SHA1Context *, const uint8_t *, unsigned int);
+int SHA1Result(SHA1Context *, uint8_t Message_Digest[SHA1_HASHSIZE]);
+
+#endif

+ 4 - 0
src/lib/dns/tests/Makefile.am

@@ -21,13 +21,17 @@ run_unittests_SOURCES += rdata_opt_unittest.cc
 run_unittests_SOURCES += rdata_dnskey_unittest.cc
 run_unittests_SOURCES += rdata_ds_unittest.cc
 run_unittests_SOURCES += rdata_nsec_unittest.cc
+run_unittests_SOURCES += rdata_nsec3_unittest.cc
+run_unittests_SOURCES += rdata_nsec3param_unittest.cc
 run_unittests_SOURCES += rdata_rrsig_unittest.cc
 run_unittests_SOURCES += rrset_unittest.cc rrsetlist_unittest.cc
 run_unittests_SOURCES += question_unittest.cc
 run_unittests_SOURCES += rrparamregistry_unittest.cc
 run_unittests_SOURCES += message_unittest.cc
+run_unittests_SOURCES += base32_unittest.cc
 run_unittests_SOURCES += base64_unittest.cc
 run_unittests_SOURCES += hex_unittest.cc
+run_unittests_SOURCES += sha1_unittest.cc
 run_unittests_SOURCES += tsig_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)

+ 69 - 0
src/lib/dns/tests/base32_unittest.cc

@@ -0,0 +1,69 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <stdint.h>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <dns/base32.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc::dns;
+
+namespace {
+
+typedef pair<string, string> StringPair;
+
+class Base32Test : public ::testing::Test {
+protected:
+    Base32Test() {}
+};
+
+TEST_F(Base32Test, reversibility)
+{
+    vector<uint8_t> result;
+//    const string input("H9RSFB7FPF2L8HG35CMPC765TDK23RP6");
+    const string input("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+    decodeBase32(input, result);
+    string output = encodeBase32(result);
+    EXPECT_EQ(input, output);
+}
+
+TEST_F(Base32Test, decode1)
+{
+    vector<uint8_t> result;
+    const std::string input("000G40O40K30E209185GO38E1S8124GJ");
+    decodeBase32(input, result);
+    EXPECT_EQ(20, result.size());
+    for (uint8_t i = 0; i < 20; i++) {
+        EXPECT_EQ((int) i, (int) result[i]);
+    }
+}
+
+TEST_F(Base32Test, encode1)
+{
+    const std::string expect("000G40O40K30E209185GO38E1S8124GJ");
+    vector<uint8_t> binary;
+    for (uint8_t i = 0; i < 20; i++) {
+        binary.push_back(i);
+    }
+    string base32 = encodeBase32(binary);
+    EXPECT_EQ(expect, base32);
+}
+}

+ 118 - 0
src/lib/dns/tests/rdata_nsec3_unittest.cc

@@ -0,0 +1,118 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <string>
+
+#include <dns/base32.h>
+#include <dns/buffer.h>
+#include <dns/hex.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_NSEC3_Test : public RdataTest {
+    // there's nothing to specialize
+};
+string nsec3_txt("1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 "
+                 "NS SOA RRSIG DNSKEY NSEC3PARAM");
+
+
+TEST_F(Rdata_NSEC3_Test, toText)
+{
+    const generic::NSEC3 rdata_nsec3(nsec3_txt);
+    EXPECT_EQ(nsec3_txt, rdata_nsec3.toText());
+}
+
+TEST_F(Rdata_NSEC3_Test, badText)
+{
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1 1 ADDAFEE "
+                                            "0123456789ABCDEFGHIJKLMNOPQRSTUV "
+                                            "BIFF POW SPOON"),
+                 InvalidRRType);
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1 1 ADDAFEE "
+                                            "0123456789ABCDEFGHIJKLMNOPQRSTUV"),
+                 InvalidRRType);
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1 1 ADDAFEE "
+                                            "WXYZWXYZWXYZ=WXYZWXYZ==WXYZWXYZW "
+                                            "A NS SOA"),
+                 BadBase32String);
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1000000 1 1 ADDAFEE "
+                                            "0123456789ABCDEFGHIJKLMNOPQRSTUV "
+                                            "A NS SOA"),
+                 InvalidRdataText);
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1000000 1 ADDAFEE "
+                                            "0123456789ABCDEFGHIJKLMNOPQRSTUV "
+                                            "A NS SOA"),
+                 InvalidRdataText);
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1 1000000 ADDAFEE "
+                                            "0123456789ABCDEFGHIJKLMNOPQRSTUV "
+                                            "A NS SOA"),
+                 InvalidRdataText);
+}
+
+TEST_F(Rdata_NSEC3_Test, createFromWire)
+{
+    const generic::NSEC3 rdata_nsec3(nsec3_txt);
+    EXPECT_EQ(0, rdata_nsec3.compare(
+                  *rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
+                                        "testdata/rdata_nsec3_fromWire1")));
+
+    // Too short RDLENGTH
+    EXPECT_THROW(rdataFactoryFromFile(RRType::NSEC3(), RRClass::IN(),
+                                      "testdata/rdata_nsec3_fromWire2"),
+                 InvalidRdataLength);
+}
+
+TEST_F(Rdata_NSEC3_Test, toWireRenderer)
+{
+    renderer.skip(2);
+    const generic::NSEC3 rdata_nsec3(nsec3_txt);
+    rdata_nsec3.toWire(renderer);
+
+    vector<unsigned char> data;
+    UnitTestUtil::readWireData("testdata/rdata_nsec3_fromWire1", data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        static_cast<const uint8_t *>(obuffer.getData()) + 2,
+                        obuffer.getLength() - 2, &data[2], data.size() - 2);
+}
+
+TEST_F(Rdata_NSEC3_Test, toWireBuffer)
+{
+    const generic::NSEC3 rdata_nsec3(nsec3_txt);
+    rdata_nsec3.toWire(obuffer);
+}
+
+TEST_F(Rdata_NSEC3_Test, assign)
+{
+    generic::NSEC3 rdata_nsec3(nsec3_txt);
+    generic::NSEC3 other_nsec3 = rdata_nsec3;
+    EXPECT_EQ(0, rdata_nsec3.compare(other_nsec3));
+}
+
+}

+ 98 - 0
src/lib/dns/tests/rdata_nsec3param_unittest.cc

@@ -0,0 +1,98 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <string>
+
+#include <dns/base32.h>
+#include <dns/buffer.h>
+#include <dns/hex.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_NSEC3PARAM_Test : public RdataTest {
+    // there's nothing to specialize
+};
+string nsec3param_txt("1 0 1 D399EAAB");
+
+TEST_F(Rdata_NSEC3PARAM_Test, toText)
+{
+    const generic::NSEC3PARAM rdata_nsec3param(nsec3param_txt);
+    EXPECT_EQ(nsec3param_txt, rdata_nsec3param.toText());
+}
+
+TEST_F(Rdata_NSEC3PARAM_Test, badText)
+{
+    EXPECT_THROW(generic::NSEC3PARAM rdata_nsec3param("1 1 1 SPORK"),
+                 BadHexString);
+    EXPECT_THROW(generic::NSEC3PARAM rdata_nsec3param("100000 1 1 ADDAFEE"),
+                 InvalidRdataText);
+    EXPECT_THROW(generic::NSEC3PARAM rdata_nsec3param("1 100000 1 ADDAFEE"),
+                 InvalidRdataText);
+    EXPECT_THROW(generic::NSEC3PARAM rdata_nsec3param("1 1 100000 ADDAFEE"),
+                 InvalidRdataText);
+    EXPECT_THROW(generic::NSEC3PARAM rdata_nsec3param("1"),
+                 InvalidRdataText);
+}
+
+TEST_F(Rdata_NSEC3PARAM_Test, createFromWire)
+{
+    const generic::NSEC3PARAM rdata_nsec3param(nsec3param_txt);
+    EXPECT_EQ(0, rdata_nsec3param.compare(
+                  *rdataFactoryFromFile(RRType::NSEC3PARAM(), RRClass::IN(),
+                                       "testdata/rdata_nsec3param_fromWire1")));
+}
+
+TEST_F(Rdata_NSEC3PARAM_Test, toWireRenderer)
+{
+    renderer.skip(2);
+    const generic::NSEC3PARAM rdata_nsec3param(nsec3param_txt);
+    rdata_nsec3param.toWire(renderer);
+
+    vector<unsigned char> data;
+    UnitTestUtil::readWireData("testdata/rdata_nsec3param_fromWire1", data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        static_cast<const uint8_t *>(obuffer.getData()) + 2,
+                        obuffer.getLength() - 2, &data[2], data.size() - 2);
+}
+
+TEST_F(Rdata_NSEC3PARAM_Test, toWireBuffer)
+{
+    const generic::NSEC3PARAM rdata_nsec3param(nsec3param_txt);
+    rdata_nsec3param.toWire(obuffer);
+}
+
+TEST_F(Rdata_NSEC3PARAM_Test, assign)
+{
+    generic::NSEC3PARAM rdata_nsec3param(nsec3param_txt);
+    generic::NSEC3PARAM other_nsec3param = rdata_nsec3param;
+    EXPECT_EQ(0, rdata_nsec3param.compare(other_nsec3param));
+}
+
+}

+ 110 - 0
src/lib/dns/tests/sha1_unittest.cc

@@ -0,0 +1,110 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <stdint.h>
+#include <string>
+
+#include <dns/sha1.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+
+namespace {
+class Sha1Test : public ::testing::Test {
+protected:
+    Sha1Test() {}
+};
+
+// Tests copied from RFC 3174
+TEST_F(Sha1Test, Test1) {
+    SHA1Context sha;
+    uint8_t digest[SHA1_HASHSIZE];
+    uint8_t expected[SHA1_HASHSIZE] = {
+        0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
+        0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d
+    };
+
+    EXPECT_EQ(0, SHA1Reset(&sha));
+    EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) "abc", 3));
+    EXPECT_EQ(0, SHA1Result(&sha, digest));
+    for (int i = 0; i < SHA1_HASHSIZE; i++) {
+        EXPECT_EQ(digest[i], expected[i]);
+    }
+}
+
+TEST_F(Sha1Test, Test2) {
+    SHA1Context sha;
+    string test("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
+    uint8_t digest[SHA1_HASHSIZE];
+    uint8_t expected[SHA1_HASHSIZE] = {
+        0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae,
+        0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1
+    };
+
+    EXPECT_EQ(0, SHA1Reset(&sha));
+    EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) test.c_str(),
+                           test.length()));
+    EXPECT_EQ(0, SHA1Result(&sha, digest));
+    for (int i = 0; i < SHA1_HASHSIZE; i++) {
+        EXPECT_EQ(digest[i], expected[i]);
+    }
+}
+
+TEST_F(Sha1Test, Test3) {
+    SHA1Context sha;
+    uint8_t digest[SHA1_HASHSIZE];
+    uint8_t expected[SHA1_HASHSIZE] = {
+        0x34, 0xaa, 0x97, 0x3c, 0xd4, 0xc4, 0xda, 0xa4, 0xf6, 0x1e,
+        0xeb, 0x2b, 0xdb, 0xad, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6f
+    };
+
+    EXPECT_EQ(0, SHA1Reset(&sha));
+    for (int i = 0; i < 1000000; i++) {
+        EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) "a", 1));
+    }
+    EXPECT_EQ(0, SHA1Result(&sha, digest));
+    for (int i = 0; i < SHA1_HASHSIZE; i++) {
+        EXPECT_EQ(digest[i], expected[i]);
+    }
+}
+
+TEST_F(Sha1Test, Test4) {
+    SHA1Context sha;
+    string test("01234567012345670123456701234567"
+                "01234567012345670123456701234567");
+    uint8_t digest[SHA1_HASHSIZE];
+    uint8_t expected[SHA1_HASHSIZE] = {
+        0xde, 0xa3, 0x56, 0xa2, 0xcd, 0xdd, 0x90, 0xc7, 0xa7, 0xec,
+        0xed, 0xc5, 0xeb, 0xb5, 0x63, 0x93, 0x4f, 0x46, 0x04, 0x52
+    };
+
+    EXPECT_EQ(0, SHA1Reset(&sha));
+    for (int i = 0; i < 10; i++) {
+        EXPECT_EQ(0, SHA1Input(&sha, (const uint8_t *) test.c_str(),
+                               test.length()));
+    }
+    EXPECT_EQ(0, SHA1Result(&sha, digest));
+    for (int i = 0; i < SHA1_HASHSIZE; i++) {
+        EXPECT_EQ(digest[i], expected[i]);
+    }
+}
+}
+

+ 7 - 0
src/lib/dns/tests/testdata/rdata_nsec3_fromWire1

@@ -0,0 +1,7 @@
+# RDLENGTH, 39 bytes
+00 27
+# NSEC3 record:
+# 1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 NS SOA RRSIG DNSKEY NSEC3PARAM
+01 01 00 01 04 d3 99 ea ab 14 8a 77 c7 ac ef cb
+c5 54 46 03 2b 2d 96 1c c5 eb 68 21 ef 26 00 07
+22 00 00 00 00 02 90

+ 12 - 0
src/lib/dns/tests/testdata/rdata_nsec3_fromWire2

@@ -0,0 +1,12 @@
+#
+# NSEC3 RDATA with a bogus RDLEN (too short)
+#
+
+# RDLENGTH, 29 bytes (should be 39)
+00 1e
+
+# NSEC3 record:
+# 1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 NS SOA RRSIG DNSKEY NSEC3PARAM
+01 01 00 01 04 d3 99 ea ab 14 8a 77 c7 ac ef cb
+c5 54 46 03 2b 2d 96 1c c5 eb 68 21 ef 26 00 07
+22 00 00 00 00 02 90

+ 5 - 0
src/lib/dns/tests/testdata/rdata_nsec3param_fromWire1

@@ -0,0 +1,5 @@
+# RDLENGTH, 9 bytes
+00 09
+# NSEC3PARAM record
+# 1 0 1 D399EAAB
+01 00 00 01 04 d3 99 ea ab