]> git.ipfire.org Git - thirdparty/ldns.git/commitdiff
merger of nsec3 branch
authorJelte Jansen <jeltejan@NLnetLabs.nl>
Wed, 1 Aug 2007 14:50:30 +0000 (14:50 +0000)
committerJelte Jansen <jeltejan@NLnetLabs.nl>
Wed, 1 Aug 2007 14:50:30 +0000 (14:50 +0000)
(nsec3 not implemented in the new chaser code yet, that will be next step)

30 files changed:
Changelog
Makefile.in
README.NSEC3 [new file with mode: 0644]
compat/b32_ntop.c [new file with mode: 0644]
compat/b32_pton.c [new file with mode: 0644]
compat/b64_ntop.c
configure.ac
dnssec.c
drill/chasetrace.c
drill/dnssec.c
drill/drill.c
drill/drill.h.in
drill/securetrace.c
error.c
examples/ldns-signzone.c
examples/nsd-test/nsec3-covers.c [new file with mode: 0644]
host2str.c
keys.c
ldns/dnssec.h
ldns/error.h
ldns/keys.h
ldns/rdata.h
ldns/rr.h
ldns/str2host.h
rdata.c
rr.c
str2host.c
test/14-unit-tests-base.tpkg [new file with mode: 0644]
util.c
wire2host.c

index 10246bb19bdddb9efacded569ca9954150f5c7b7..eb80ae2560d50183a9fcedc574d187058741dc26 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,4 @@
+<<<<<<< .working
 1.x
        * API changes:
          - various arguments have the keyword const now
                - made KSK check more resilient
 
 
-7 Jul 2006: 1.1.0: ldns-team
+* 1.1.X:
+       * ldns-walk now support dnames with maximum label length
+       * capitalization issues in sign/verify/nsec creation are fixed
+       * ldnsd now takes an extra argument containing the address to listen on
+       * signing no longer signs every rrset with KSK's, but only the DNSKEY rrset
+       * ported to Solaris 10
+        * LOC RR type has been fixed
+       * added ldns_send_buffer() function
+
+       Drill:
+       * drill prints error on failed axfr.
+       * drill now accepts mangled packets with -f
+       * old -c option (use tcp) changed to -t
+       * -c option to specify alternative resolv.conf file added
+       * chaser now stops at root when no trusted keys are found
+         instead of looping forever trying to find the DS for .
+
+
+31 Apr 2006: 1.1.0: ldns-team
        * Added tutorials and an introduction to the documentation
        * Added include/ and lib/ dirs so that you can compile against ldns
          without installing ldns on your system
index be57bd5ed0a8205fd9ce49d61ed809c96f1d2142..83ae7ebf4453d6ff41dd8b82c83564e0911d5470 100644 (file)
@@ -202,6 +202,12 @@ b64_pton$U.o:      $(srcdir)/compat/b64_pton.c
 b64_ntop$U.o:  $(srcdir)/compat/b64_ntop.c
        $(COMP_LIB) -c $(srcdir)/compat/b64_ntop.c -o $@
 
+b32_pton$U.o:  $(srcdir)/compat/b32_pton.c
+       $(COMP_LIB) -c $(srcdir)/compat/b32_pton.c -o $@
+
+b32_ntop$U.o:  $(srcdir)/compat/b32_ntop.c
+       $(COMP_LIB) -c $(srcdir)/compat/b32_ntop.c -o $@
+
 malloc$U.o:    $(srcdir)/compat/malloc.c
        $(COMP_LIB) -c $(srcdir)/compat/malloc.c -o $@
 
diff --git a/README.NSEC3 b/README.NSEC3
new file mode 100644 (file)
index 0000000..72d6fed
--- /dev/null
@@ -0,0 +1,42 @@
+
+NSEC3 Workshop Notes
+
+To build this library and drill, perform the following actions:
+
+./configure 
+make
+cd drill
+./configure
+make
+
+For Linux:
+export LD_LIBRARY_PATH=<path to base dir>/lib
+
+For OSX:
+export DYLD_LIBRARY_PATH=<path to base dir>/lib
+
+
+On OSX 10.4, you might need to set
+MACOSX_DEPLOYMENT_TARGET=10.4 in your environment
+
+
+Examples of drill usage:
+
+drill -TD n3.n3s.ws.nsec3.org. -k ~/nsec3/Kws.nsec3.org.+005.+27311.key 
+
+Performs a secure (-D) trace (-T) with a trusted key (-k).
+
+Another useful argument is -d <name>, in which case the tracer will start at that zone instead of the root.
+
+For example
+drill -TD ok.ok.ok.nsec3.jelte.nlnetlabs.nl -d jelte.nlnetlabs.nl
+
+-V (number) changes the verbosity, values range from 0 to 5.
+
+For each zone, some data is printed, with it's status, either [T] [S] or [B]:
+[T] Trusted, the data is verified and has a chain to a trusted key
+[S] Signed, the data verifies with it's signature but does NOT have a chain to a trusted key
+[B] Bogus, the data did not verify.
+
+Try to raise the verbosity to see a more detailed description.
+
diff --git a/compat/b32_ntop.c b/compat/b32_ntop.c
new file mode 100644 (file)
index 0000000..a8dbe21
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+static const char Base32[] =
+       "abcdefghijklmnopqrstuvwxyz234567";
+/*     "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";*/
+/*       00000000001111111111222222222233
+         01234567890123456789012345678901*/
+static const char Base32_extended_hex[] =
+/*     "0123456789ABCDEFGHIJKLMNOPQRSTUV";*/
+       "0123456789abcdefghijklmnopqrstuv";
+static const char Pad32 = '=';
+
+/* (From RFC3548 and draft-josefsson-rfc3548bis-00.txt)
+5.  Base 32 Encoding
+
+   The Base 32 encoding is designed to represent arbitrary sequences of
+   octets in a form that needs to be case insensitive but need not be
+   humanly readable.
+
+   A 33-character subset of US-ASCII is used, enabling 5 bits to be
+   represented per printable character.  (The extra 33rd character, "=",
+   is used to signify a special processing function.)
+
+   The encoding process represents 40-bit groups of input bits as output
+   strings of 8 encoded characters.  Proceeding from left to right, a
+   40-bit input group is formed by concatenating 5 8bit input groups.
+   These 40 bits are then treated as 8 concatenated 5-bit groups, each
+   of which is translated into a single digit in the base 32 alphabet.
+   When encoding a bit stream via the base 32 encoding, the bit stream
+   must be presumed to be ordered with the most-significant-bit first.
+   That is, the first bit in the stream will be the high-order bit in
+   the first 8bit byte, and the eighth bit will be the low-order bit in
+   the first 8bit byte, and so on.
+
+   Each 5-bit group is used as an index into an array of 32 printable
+   characters.  The character referenced by the index is placed in the
+   output string.  These characters, identified in Table 3, below, are
+   selected from US-ASCII digits and uppercase letters.
+
+                      Table 3: The Base 32 Alphabet
+
+         Value Encoding  Value Encoding  Value Encoding  Value Encoding
+             0 A             9 J            18 S            27 3
+             1 B            10 K            19 T            28 4
+             2 C            11 L            20 U            29 5
+             3 D            12 M            21 V            30 6
+             4 E            13 N            22 W            31 7
+             5 F            14 O            23 X
+             6 G            15 P            24 Y         (pad) =
+             7 H            16 Q            25 Z
+             8 I            17 R            26 2
+
+
+   Special processing is performed if fewer than 40 bits are available
+   at the end of the data being encoded.  A full encoding quantum is
+   always completed at the end of a body.  When fewer than 40 input bits
+   are available in an input group, zero bits are added (on the right)
+   to form an integral number of 5-bit groups.  Padding at the end of
+   the data is performed using the "=" character.  Since all base 32
+   input is an integral number of octets, only the following cases can
+   arise:
+
+   (1) the final quantum of encoding input is an integral multiple of 40
+   bits; here, the final unit of encoded output will be an integral
+   multiple of 8 characters with no "=" padding,
+
+   (2) the final quantum of encoding input is exactly 8 bits; here, the
+   final unit of encoded output will be two characters followed by six
+   "=" padding characters,
+
+   (3) the final quantum of encoding input is exactly 16 bits; here, the
+   final unit of encoded output will be four characters followed by four
+   "=" padding characters,
+
+   (4) the final quantum of encoding input is exactly 24 bits; here, the
+   final unit of encoded output will be five characters followed by
+   three "=" padding characters, or
+
+   (5) the final quantum of encoding input is exactly 32 bits; here, the
+   final unit of encoded output will be seven characters followed by one
+   "=" padding character.
+
+
+6.  Base 32 Encoding with Extended Hex Alphabet
+
+   The following description of base 32 is due to [7].  This encoding
+   should not be regarded as the same as the "base32" encoding, and
+   should not be referred to as only "base32".
+
+   One property with this alphabet, that the base64 and base32 alphabet
+   lack, is that encoded data maintain its sort order when the encoded
+   data is compared bit-wise.
+
+   This encoding is identical to the previous one, except for the
+   alphabet.  The new alphabet is found in table 4.
+
+                     Table 4: The "Extended Hex" Base 32 Alphabet
+
+         Value Encoding  Value Encoding  Value Encoding  Value Encoding
+             0 0             9 9            18 I            27 R
+             1 1            10 A            19 J            28 S
+             2 2            11 B            20 K            29 T
+             3 3            12 C            21 L            30 U
+             4 4            13 D            22 M            31 V
+             5 5            14 E            23 N
+             6 6            15 F            24 O         (pad) =
+             7 7            16 G            25 P
+             8 8            17 H            26 Q
+
+*/
+
+
+int
+b32_ntop_ar(uint8_t const *src, size_t srclength, char *target, size_t targsize, const char B32_ar[]) {
+       size_t datalength = 0;
+       uint8_t input[5];
+       uint8_t output[8];
+        memset(output, 0, 8);
+       size_t i;
+
+       while (4 < srclength) {
+               input[0] = *src++;
+               input[1] = *src++;
+               input[2] = *src++;
+               input[3] = *src++;
+               input[4] = *src++;
+               srclength -= 5;
+
+               output[0] = (input[0] & 0xf8) >> 3;
+               output[1] = ((input[0] & 0x07) << 2) + ((input[1] & 0xc0) >> 6);
+               output[2] = (input[1] & 0x3e) >> 1;
+               output[3] = ((input[1] & 0x01) << 4) + ((input[2] & 0xf0) >> 4);
+               output[4] = ((input[2] & 0x0f) << 1) + ((input[3] & 0x80) >> 7);
+               output[5] = (input[3] & 0x7c) >> 2;
+               output[6] = ((input[3] & 0x03) << 3) + ((input[4] & 0xe0) >> 5);
+               output[7] = (input[4] & 0x1f);
+
+               assert(output[0] < 32);
+               assert(output[1] < 32);
+               assert(output[2] < 32);
+               assert(output[3] < 32);
+               assert(output[4] < 32);
+               assert(output[5] < 32);
+               assert(output[6] < 32);
+               assert(output[7] < 32);
+
+               if (datalength + 8 > targsize) {
+                       return (-1);
+               }
+               target[datalength++] = B32_ar[output[0]];
+               target[datalength++] = B32_ar[output[1]];
+               target[datalength++] = B32_ar[output[2]];
+               target[datalength++] = B32_ar[output[3]];
+               target[datalength++] = B32_ar[output[4]];
+               target[datalength++] = B32_ar[output[5]];
+               target[datalength++] = B32_ar[output[6]];
+               target[datalength++] = B32_ar[output[7]];
+       }
+    
+       /* Now we worry about padding. */
+       if (0 != srclength) {
+               /* Get what's left. */
+               input[0] = input[1] = input[2] = input[3] = input[4] = (uint8_t) '\0';
+               for (i = 0; i < srclength; i++)
+                       input[i] = *src++;
+       
+               output[0] = (input[0] & 0xf8) >> 3;
+               assert(output[0] < 32);
+               if (srclength >= 1) {
+                       output[1] = ((input[0] & 0x07) << 2) + ((input[1] & 0xc0) >> 6);
+                       assert(output[1] < 32);
+                       output[2] = (input[1] & 0x3e) >> 1;
+                       assert(output[2] < 32);
+               }
+               if (srclength >= 2) {
+                       output[3] = ((input[1] & 0x01) << 4) + ((input[2] & 0xf0) >> 4);
+                       assert(output[3] < 32);
+               }
+               if (srclength >= 3) {
+                       output[4] = ((input[2] & 0x0f) << 1) + ((input[3] & 0x80) >> 7);
+                       assert(output[4] < 32);
+                       output[5] = (input[3] & 0x7c) >> 2;
+                       assert(output[5] < 32);
+               }
+               if (srclength >= 4) {
+                       output[6] = ((input[3] & 0x03) << 3) + ((input[4] & 0xe0) >> 5);
+                       assert(output[6] < 32);
+               }
+
+
+               if (datalength + 1 > targsize) {
+                       return (-2);
+               }
+               target[datalength++] = B32_ar[output[0]];
+               if (srclength >= 1) {
+                       target[datalength++] = B32_ar[output[1]];
+                       if (srclength == 1 && output[2] == 0) {
+                               target[datalength++] = Pad32;
+                       } else {
+                               target[datalength++] = B32_ar[output[2]];
+                       }
+               } else {
+                       target[datalength++] = Pad32;
+                       target[datalength++] = Pad32;
+               }
+               if (srclength >= 2) {
+                       target[datalength++] = B32_ar[output[3]];
+               } else {
+                       target[datalength++] = Pad32;
+               }
+               if (srclength >= 3) {
+                       target[datalength++] = B32_ar[output[4]];
+                       if (srclength == 3 && output[5] == 0) {
+                               target[datalength++] = Pad32;
+                       } else {
+                               target[datalength++] = B32_ar[output[5]];
+                       }
+               } else {
+                       target[datalength++] = Pad32;
+                       target[datalength++] = Pad32;
+               }
+               if (srclength >= 4) {
+                       target[datalength++] = B32_ar[output[6]];
+               } else {
+                       target[datalength++] = Pad32;
+               }
+               target[datalength++] = Pad32;
+       }
+       if (datalength > targsize) {
+               return (-3);
+       }
+       target[datalength] = '\0';      /* Returned value doesn't count \0. */
+       return (int) (datalength);
+}
+
+int
+b32_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
+       return b32_ntop_ar(src, srclength, target, targsize, Base32);
+}
+
+int
+b32_ntop_extended_hex(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
+       return b32_ntop_ar(src, srclength, target, targsize, Base32_extended_hex);
+}
+
diff --git a/compat/b32_pton.c b/compat/b32_pton.c
new file mode 100644 (file)
index 0000000..ee64d0c
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*     "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";*/
+static const char Base32[] =
+       "abcdefghijklmnopqrstuvwxyz234567";
+/*     "0123456789ABCDEFGHIJKLMNOPQRSTUV";*/
+static const char Base32_extended_hex[] =
+       "0123456789abcdefghijklmnopqrstuv";
+static const char Pad32 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+5.  Base 32 Encoding
+
+   The Base 32 encoding is designed to represent arbitrary sequences of
+   octets in a form that needs to be case insensitive but need not be
+   humanly readable.
+
+   A 33-character subset of US-ASCII is used, enabling 5 bits to be
+   represented per printable character.  (The extra 33rd character, "=",
+   is used to signify a special processing function.)
+
+   The encoding process represents 40-bit groups of input bits as output
+   strings of 8 encoded characters.  Proceeding from left to right, a
+   40-bit input group is formed by concatenating 5 8bit input groups.
+   These 40 bits are then treated as 8 concatenated 5-bit groups, each
+   of which is translated into a single digit in the base 32 alphabet.
+   When encoding a bit stream via the base 32 encoding, the bit stream
+   must be presumed to be ordered with the most-significant-bit first.
+   That is, the first bit in the stream will be the high-order bit in
+   the first 8bit byte, and the eighth bit will be the low-order bit in
+   the first 8bit byte, and so on.
+
+   Each 5-bit group is used as an index into an array of 32 printable
+   characters.  The character referenced by the index is placed in the
+   output string.  These characters, identified in Table 3, below, are
+   selected from US-ASCII digits and uppercase letters.
+
+                      Table 3: The Base 32 Alphabet
+
+         Value Encoding  Value Encoding  Value Encoding  Value Encoding
+             0 A             9 J            18 S            27 3
+             1 B            10 K            19 T            28 4
+             2 C            11 L            20 U            29 5
+             3 D            12 M            21 V            30 6
+             4 E            13 N            22 W            31 7
+             5 F            14 O            23 X
+             6 G            15 P            24 Y         (pad) =
+             7 H            16 Q            25 Z
+             8 I            17 R            26 2
+
+
+   Special processing is performed if fewer than 40 bits are available
+   at the end of the data being encoded.  A full encoding quantum is
+   always completed at the end of a body.  When fewer than 40 input bits
+   are available in an input group, zero bits are added (on the right)
+   to form an integral number of 5-bit groups.  Padding at the end of
+   the data is performed using the "=" character.  Since all base 32
+   input is an integral number of octets, only the following cases can
+   arise:
+
+   (1) the final quantum of encoding input is an integral multiple of 40
+   bits; here, the final unit of encoded output will be an integral
+   multiple of 8 characters with no "=" padding,
+
+   (2) the final quantum of encoding input is exactly 8 bits; here, the
+   final unit of encoded output will be two characters followed by six
+   "=" padding characters,
+
+   (3) the final quantum of encoding input is exactly 16 bits; here, the
+   final unit of encoded output will be four characters followed by four
+   "=" padding characters,
+
+   (4) the final quantum of encoding input is exactly 24 bits; here, the
+   final unit of encoded output will be five characters followed by
+   three "=" padding characters, or
+
+   (5) the final quantum of encoding input is exactly 32 bits; here, the
+   final unit of encoded output will be seven characters followed by one
+   "=" padding character.
+
+
+6.  Base 32 Encoding with Extended Hex Alphabet
+
+   The following description of base 32 is due to [7].  This encoding
+   should not be regarded as the same as the "base32" encoding, and
+   should not be referred to as only "base32".
+
+   One property with this alphabet, that the base32 and base32 alphabet
+   lack, is that encoded data maintain its sort order when the encoded
+   data is compared bit-wise.
+
+   This encoding is identical to the previous one, except for the
+   alphabet.  The new alphabet is found in table 4.
+
+                     Table 4: The "Extended Hex" Base 32 Alphabet
+
+         Value Encoding  Value Encoding  Value Encoding  Value Encoding
+             0 0             9 9            18 I            27 R
+             1 1            10 A            19 J            28 S
+             2 2            11 B            20 K            29 T
+             3 3            12 C            21 L            30 U
+             4 4            13 D            22 M            31 V
+             5 5            14 E            23 N
+             6 6            15 F            24 O         (pad) =
+             7 7            16 G            25 P
+             8 8            17 H            26 Q
+
+
+
+
+*/
+/* skips all whitespace anywhere.
+   converts characters, four at a time, starting at (or after)
+   src from base - 32 numbers into three 8 bit bytes in the target area.
+   it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b32_pton_ar(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize, const char B32_ar[])
+{
+       int tarindex, state, ch;
+       char *pos;
+       int i = 0;
+
+       state = 0;
+       tarindex = 0;
+       
+       while ((ch = *src++) != '\0' && (i == 0 || i < (int) hashed_owner_str_len)) {
+               i++;
+               ch = tolower(ch);
+               if (isspace((unsigned char)ch))        /* Skip whitespace anywhere. */
+                       continue;
+
+               if (ch == Pad32)
+                       break;
+
+               pos = strchr(B32_ar, ch);
+               if (pos == 0) {
+                       /* A non-base32 character. */
+                       return (-ch);
+               }
+
+               switch (state) {
+               case 0:
+                       if (target) {
+                               if ((size_t)tarindex >= targsize) {
+                                       return (-2);
+                               }
+                               target[tarindex] = (pos - B32_ar) << 3;
+                       }
+                       state = 1;
+                       break;
+               case 1:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize) {
+                                       return (-3);
+                               }
+                               target[tarindex]   |=  (pos - B32_ar) >> 2;
+                               target[tarindex+1]  = ((pos - B32_ar) & 0x03)
+                                                       << 6 ;
+                       }
+                       tarindex++;
+                       state = 2;
+                       break;
+               case 2:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize) {
+                                       return (-4);
+                               }
+                               target[tarindex]   |=  (pos - B32_ar) << 1;
+                       }
+                       /*tarindex++;*/
+                       state = 3;
+                       break;
+               case 3:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize) {
+                                       return (-5);
+                               }
+                               target[tarindex]   |=  (pos - B32_ar) >> 4;
+                               target[tarindex+1]  = ((pos - B32_ar) & 0x0f) << 4 ;
+                       }
+                       tarindex++;
+                       state = 4;
+                       break;
+               case 4:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize) {
+                                       return (-6);
+                               }
+                               target[tarindex]   |=  (pos - B32_ar) >> 1;
+                               target[tarindex+1]  = ((pos - B32_ar) & 0x01)
+                                                       << 7 ;
+                       }
+                       tarindex++;
+                       state = 5;
+                       break;
+               case 5:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize) {
+                                       return (-7);
+                               }
+                               target[tarindex]   |=  (pos - B32_ar) << 2;
+                       }
+                       state = 6;
+                       break;
+               case 6:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize) {
+                                       return (-8);
+                               }
+                               target[tarindex]   |=  (pos - B32_ar) >> 3;
+                               target[tarindex+1]  = ((pos - B32_ar) & 0x07)
+                                                       << 5 ;
+                       }
+                       tarindex++;
+                       state = 7;
+                       break;
+               case 7:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize) {
+                                       return (-9);
+                               }
+                               target[tarindex]   |=  (pos - B32_ar);
+                       }
+                       tarindex++;
+                       state = 0;
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+       /*
+        * We are done decoding Base-32 chars.  Let's see if we ended
+        * on a byte boundary, and/or with erroneous trailing characters.
+        */
+
+       if (ch == Pad32) {              /* We got a pad char. */
+               ch = *src++;            /* Skip it, get next. */
+               switch (state) {
+               case 0:         /* Invalid = in first position */
+               case 1:         /* Invalid = in second position */
+                       return (-10);
+
+               case 2:         /* Valid, means one byte of info */
+               case 3:
+                       /* Skip any number of spaces. */
+                       for ((void)NULL; ch != '\0'; ch = *src++)
+                               if (!isspace((unsigned char)ch))
+                                       break;
+                       /* Make sure there is another trailing = sign. */
+                       if (ch != Pad32) {
+                               return (-11);
+                       }
+                       ch = *src++;            /* Skip the = */
+                       /* Fall through to "single trailing =" case. */
+                       /* FALLTHROUGH */
+
+               case 4:         /* Valid, means two bytes of info */
+               case 5:
+               case 6:
+                       /*
+                        * We know this char is an =.  Is there anything but
+                        * whitespace after it?
+                        */
+                       for ((void)NULL; ch != '\0'; ch = *src++)
+                               if (!(isspace((unsigned char)ch) || ch == '=')) {
+                                       return (-12);
+                               }
+
+               case 7:         /* Valid, means three bytes of info */
+                       /*
+                        * We know this char is an =.  Is there anything but
+                        * whitespace after it?
+                        */
+                       for ((void)NULL; ch != '\0'; ch = *src++)
+                               if (!isspace((unsigned char)ch)) {
+                                       return (-13);
+                               }
+
+                       /*
+                        * Now make sure for cases 2 and 3 that the "extra"
+                        * bits that slopped past the last full byte were
+                        * zeros.  If we don't check them, they become a
+                        * subliminal channel.
+                        */
+                       if (target && target[tarindex] != 0) {
+                               return (-14);
+                       }
+               }
+       } else {
+               /*
+                * We ended by seeing the end of the string.  Make sure we
+                * have no partial bytes lying around.
+                */
+               if (state != 0)
+                       return (-15);
+       }
+
+       return (tarindex);
+}
+
+int
+b32_pton(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize)
+{
+       return b32_pton_ar(src, hashed_owner_str_len, target, targsize, Base32);
+}
+
+int
+b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize)
+{
+       return b32_pton_ar(src, hashed_owner_str_len, target, targsize, Base32_extended_hex);
+}
+
index 7f680108279127e52f1667a535e98928425f989b..6c65f9bf6d2577413bd29661438dd631b3cfe729 100644 (file)
@@ -57,6 +57,9 @@
 
 #define Assert(Cond) if (!(Cond)) abort()
 
+/*       0000000000111111111122222222223333333333444444444455555555556666
+         0123456789012345678901234567890123456789012345678901234567890123
+*/
 static const char Base64[] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 static const char Pad64 = '=';
index 6832d24eed4d1bb525092d56d294a97a1f6cf8c6..c3778cdb61585d6fbca256cbda355538f399a875 100644 (file)
@@ -350,6 +350,8 @@ AC_FUNC_REALLOC
 
 AC_REPLACE_FUNCS(b64_pton)
 AC_REPLACE_FUNCS(b64_ntop)
+AC_REPLACE_FUNCS(b32_pton)
+AC_REPLACE_FUNCS(b32_ntop)
 AC_REPLACE_FUNCS(timegm)
 AC_REPLACE_FUNCS(gmtime_r)
 AC_REPLACE_FUNCS(ctime_r)
@@ -432,6 +434,37 @@ static inline size_t b64_pton_calculate_size(size_t srcsize)
        return ((((srcsize / 4) * 3) - 2) + 2);
 }
 #endif /* !B64_NTOP */
+
+#ifndef B32_NTOP
+int b32_ntop(uint8_t const *src, size_t srclength,
+            char *target, size_t targsize);
+int b32_ntop_extended_hex(uint8_t const *src, size_t srclength,
+            char *target, size_t targsize);
+/**
+ * calculates the size needed to store the result of b32_ntop
+ */
+/*@unused@*/
+static inline size_t b32_ntop_calculate_size(size_t srcsize)
+{
+       size_t result = ((((srcsize / 5) * 8) - 2) + 2);
+       return result;
+}
+#endif /* !B32_PTON */
+#ifndef B32_PTON
+int b32_pton(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize);
+int b32_pton_extended_hex(char const *src, size_t hashed_owner_str_len, uint8_t *target, size_t targsize);
+/**
+ * calculates the size needed to store the result of b32_pton
+ */
+/*@unused@*/
+static inline size_t b32_pton_calculate_size(size_t srcsize)
+{
+       size_t result = ((((srcsize) / 8) * 5));
+       return result;
+}
+#endif /* !B32_NTOP */
+
+
 #ifndef TIMEGM
 #include <time.h>
 time_t timegm (struct tm *tm);
index f8d97cf4160accfde991ee23b8fdd25593691db7..bbda9264b707eb6fc65abbceeb616dc73d2219e7 100644 (file)
--- a/dnssec.c
+++ b/dnssec.c
@@ -834,10 +834,11 @@ ldns_verify_rrsig_buffers(ldns_buffer *rawsig_buf, ldns_buffer *verify_buf,
                /* check for right key */
                switch(algo) {
                        case LDNS_DSA:
+                       case LDNS_DSA_NSEC3:
                                return ldns_verify_rrsig_dsa(rawsig_buf, verify_buf, key_buf);
                                break;
                        case LDNS_RSASHA1:
-                               /*return ldns_verify_rrsig_rsasha1(rawsig_buf, verify_buf, key_buf);*/
+                       case LDNS_RSASHA1_NSEC3:
                                return ldns_verify_rrsig_rsasha1(rawsig_buf, verify_buf, key_buf);
                                break;
                        case LDNS_RSAMD5:
@@ -898,6 +899,8 @@ ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_lis
        /* check if the typecovered is equal to the type checked */
        if (ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rrsig)) !=
                        ldns_rr_get_type(ldns_rr_list_rr(rrset_clone, 0))) {
+               ldns_rr_list_deep_free(rrset_clone);
+               ldns_rr_list_deep_free(validkeys);
                return LDNS_STATUS_CRYPTO_TYPE_COVERED_ERR;
        }
        
@@ -917,18 +920,30 @@ ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_lis
                /* bad sig, expiration before inception?? Tsssg */
                ldns_buffer_free(rawsig_buf);
                ldns_buffer_free(verify_buf);
+               ldns_buffer_free(rawsig_buf);
+               ldns_buffer_free(verify_buf);
+               ldns_rr_list_deep_free(rrset_clone);
+               ldns_rr_list_deep_free(validkeys);
                return LDNS_STATUS_CRYPTO_EXPIRATION_BEFORE_INCEPTION;
        }
        if (now - inception < 0) {
                /* bad sig, inception date has passed */
                ldns_buffer_free(rawsig_buf);
                ldns_buffer_free(verify_buf);
+               ldns_buffer_free(rawsig_buf);
+               ldns_buffer_free(verify_buf);
+               ldns_rr_list_deep_free(rrset_clone);
+               ldns_rr_list_deep_free(validkeys);
                return LDNS_STATUS_CRYPTO_SIG_NOT_INCEPTED;
        }
        if (expiration - now < 0) {
                /* bad sig, expiration date has passed */
                ldns_buffer_free(rawsig_buf);
                ldns_buffer_free(verify_buf);
+               ldns_buffer_free(rawsig_buf);
+               ldns_buffer_free(verify_buf);
+               ldns_rr_list_deep_free(rrset_clone);
+               ldns_rr_list_deep_free(validkeys);
                return LDNS_STATUS_CRYPTO_SIG_EXPIRED;
        }
        
@@ -936,6 +951,8 @@ ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_lis
        if (ldns_rdf2buffer_wire(rawsig_buf, ldns_rr_rdf(rrsig, 8)) != LDNS_STATUS_OK) {
                ldns_buffer_free(rawsig_buf);
                ldns_buffer_free(verify_buf);
+               ldns_rr_list_deep_free(rrset_clone);
+               ldns_rr_list_deep_free(validkeys);
                return LDNS_STATUS_MEM_ERR;
        }
 
@@ -947,7 +964,7 @@ ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_lis
        for(i = 0; i < ldns_rr_list_rr_count(rrset_clone); i++) {
                if (label_count < 
                        ldns_dname_label_count(
-                                       ldns_rr_owner(ldns_rr_list_rr(rrset_clone, i)))) {
+                                       ldns_rr_owner(ldns_rr_list_rr(rrset_clone, i)))) {
                        (void) ldns_str2rdf_dname(&wildcard_name, "*");
                        wildcard_chopped = ldns_rdf_clone(ldns_rr_owner(ldns_rr_list_rr(rrset_clone, i)));
                        while (label_count < ldns_dname_label_count(wildcard_chopped)) {
@@ -974,6 +991,8 @@ ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_lis
        if (ldns_rrsig2buffer_wire(verify_buf, rrsig) != LDNS_STATUS_OK) {
                ldns_buffer_free(rawsig_buf);
                ldns_buffer_free(verify_buf);
+               ldns_rr_list_deep_free(rrset_clone);
+               ldns_rr_list_deep_free(validkeys);
                return LDNS_STATUS_MEM_ERR;
        }
 
@@ -981,6 +1000,8 @@ ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_lis
        if (ldns_rr_list2buffer_wire(verify_buf, rrset_clone) != LDNS_STATUS_OK) {
                ldns_buffer_free(rawsig_buf);
                ldns_buffer_free(verify_buf);
+               ldns_rr_list_deep_free(rrset_clone);
+               ldns_rr_list_deep_free(validkeys);
                return LDNS_STATUS_MEM_ERR;
        }
 
@@ -999,6 +1020,8 @@ ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_lis
                                ldns_buffer_free(verify_buf);
                                /* returning is bad might screw up good keys later in the list
                                   what to do? */
+                               ldns_rr_list_deep_free(rrset_clone);
+                               ldns_rr_list_deep_free(validkeys);
                                return LDNS_STATUS_MEM_ERR;
                        }
 
@@ -1008,7 +1031,7 @@ ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_lis
                                result = ldns_verify_rrsig_buffers(rawsig_buf, 
                                                verify_buf, key_buf, sig_algo);
                        } else {
-                               /* There is no else here ???? */
+                               result = LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
                        }
                        
                        ldns_buffer_free(key_buf); 
@@ -1022,11 +1045,15 @@ ldns_verify_rrsig_keylist(ldns_rr_list *rrset, ldns_rr *rrsig, const ldns_rr_lis
                                        /* couldn't push the key?? */
                                        ldns_buffer_free(rawsig_buf);
                                        ldns_buffer_free(verify_buf);
+                                       ldns_rr_list_deep_free(rrset_clone);
+                                       ldns_rr_list_deep_free(validkeys);
                                        return LDNS_STATUS_MEM_ERR;
                                }
                        } 
                } else {
-                       result = LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY;
+                       if (result == LDNS_STATUS_ERR) {
+                               result = LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY;
+                       }
                }
        }
 
@@ -1103,7 +1130,9 @@ ldns_verify_rrsig(ldns_rr_list *rrset, ldns_rr *rrsig, ldns_rr *key)
        switch(sig_algo) {
                case LDNS_RSAMD5:
                case LDNS_RSASHA1:
+               case LDNS_RSASHA1_NSEC3:
                case LDNS_DSA:
+               case LDNS_DSA_NSEC3:
                        break;
                case LDNS_DH:
                case LDNS_ECC:
@@ -1208,7 +1237,9 @@ ldns_verify_rrsig(ldns_rr_list *rrset, ldns_rr *rrsig, ldns_rr *key)
        }
         else {
                /* No keys with the corresponding keytag are found */
-               result = LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY;
+               if (result == LDNS_STATUS_ERR) {
+                       result = LDNS_STATUS_CRYPTO_NO_MATCHING_KEYTAG_DNSKEY;
+               }
        }
        /* no longer needed */
        ldns_rr_list_deep_free(rrset_clone);
@@ -1614,16 +1645,21 @@ ldns_sign_public(ldns_rr_list *rrset, ldns_key_list *keys)
                        
                        switch(ldns_key_algorithm(current_key)) {
                                case LDNS_SIGN_DSA:
+                               case LDNS_DSA_NSEC3:
                                        b64rdf = ldns_sign_public_evp(sign_buf, ldns_key_evp_key(current_key), EVP_sha1());
+/*                                     b64rdf = ldns_sign_public_dsa(sign_buf, ldns_key_dsa_key(current_key));*/
                                        break;
                                case LDNS_SIGN_RSASHA1:
+                               case LDNS_RSASHA1_NSEC3:
                                        b64rdf = ldns_sign_public_evp(sign_buf, ldns_key_evp_key(current_key), EVP_sha1());
+/*                                     b64rdf = ldns_sign_public_rsasha1(sign_buf, ldns_key_rsa_key(current_key));*/
                                        break;
                                case LDNS_SIGN_RSAMD5:
                                        b64rdf = ldns_sign_public_evp(sign_buf, ldns_key_evp_key(current_key), EVP_md5());
                                        break;
                                default:
                                        /* do _you_ know this alg? */
+                                       printf("unknown alg\n");
                                        break;
                        }
                        if (!b64rdf) {
@@ -1900,38 +1936,399 @@ ldns_create_nsec(ldns_rdf *cur_owner, ldns_rdf *next_owner, ldns_rr_list *rrs)
        return nsec;
 }
 
-bool
-ldns_nsec_bitmap_covers_type(const ldns_rdf *nsec_bitmap, ldns_rr_type type)
+ldns_rdf *
+ldns_nsec3_hash_name(ldns_rdf *name, uint8_t algorithm, uint16_t iterations, uint8_t salt_length, uint8_t *salt)
 {
-       uint8_t *bitmap;
-       uint16_t i;
-       uint8_t window_block_nr;
+       char *orig_owner_str;
+       size_t hashed_owner_str_len;
+       ldns_rdf *hashed_owner;
+       char *hashed_owner_str;
+       char *hashed_owner_b32;
+       int hashed_owner_b32_len;
+       uint32_t cur_it;
+       char *hash = NULL;
+       ldns_status status;
        
-       if (!nsec_bitmap) {
-               return false;
+       /* prepare the owner name according to the draft section bla */
+       orig_owner_str = ldns_rdf2str(name);
+       
+       /* TODO: mnemonic list for hash algs SHA-1, default to 1 now (sha1) */
+       algorithm = algorithm;
+       
+       hashed_owner_str_len = salt_length + ldns_rdf_size(name);
+       hashed_owner_str = LDNS_XMALLOC(char, hashed_owner_str_len);
+        memcpy(hashed_owner_str, ldns_rdf_data(name), ldns_rdf_size(name));
+       memcpy(hashed_owner_str + ldns_rdf_size(name), salt, salt_length);
+
+       for (cur_it = iterations + 1; cur_it > 0; cur_it--) {
+               /*xprintf_hex(hashed_owner_str, hashed_owner_str_len);*/
+               hash = (char *) SHA1((unsigned char *) hashed_owner_str, hashed_owner_str_len, NULL);
+
+               LDNS_FREE(hashed_owner_str);
+               hashed_owner_str_len = salt_length + SHA_DIGEST_LENGTH;
+               hashed_owner_str = LDNS_XMALLOC(char, hashed_owner_str_len);
+               if (!hashed_owner_str) {
+                       fprintf(stderr, "Memory error\n");
+                       abort();
+               }
+               memcpy(hashed_owner_str, hash, SHA_DIGEST_LENGTH);
+               memcpy(hashed_owner_str + SHA_DIGEST_LENGTH, salt, salt_length);
+               hashed_owner_str_len = SHA_DIGEST_LENGTH + salt_length;
+       }
+
+       LDNS_FREE(orig_owner_str);
+       LDNS_FREE(hashed_owner_str);
+       hashed_owner_str = hash;
+       hashed_owner_str_len = SHA_DIGEST_LENGTH;
+
+       hashed_owner_b32 = LDNS_XMALLOC(char, b32_ntop_calculate_size(hashed_owner_str_len) + 1);
+       hashed_owner_b32_len = (size_t) b32_ntop_extended_hex((uint8_t *) hashed_owner_str, hashed_owner_str_len, hashed_owner_b32, b32_ntop_calculate_size(hashed_owner_str_len));
+       if (hashed_owner_b32_len < 1) {
+               fprintf(stderr, "Error in base32 extended hex encoding of hashed owner name (name: ");
+               ldns_rdf_print(stderr, name);
+               fprintf(stderr, ", return code: %d)\n", hashed_owner_b32_len);
+               exit(4);
+       }
+       hashed_owner_str_len = hashed_owner_b32_len;
+        hashed_owner_b32[hashed_owner_b32_len] = '\0';
+
+       status = ldns_str2rdf_dname(&hashed_owner, hashed_owner_b32);
+       if (status != LDNS_STATUS_OK) {
+               fprintf(stderr, "Error creating rdf from %s\n", hashed_owner_b32);
+               exit(1);
        }
 
-       /* Check the bitmap if our type is there */
-       bitmap = ldns_rdf_data(nsec_bitmap);
-       window_block_nr = (uint8_t) (type / 256);
-       i = 0;
+       LDNS_FREE(hashed_owner_b32);
+       return hashed_owner;
+}
+
+void
+ldns_nsec3_add_param_rdfs(ldns_rr *rr,
+                           uint8_t algorithm, 
+                           uint8_t flags,
+                           uint16_t iterations,
+                           uint8_t salt_length,
+                           uint8_t *salt)
+{
+       ldns_rdf *salt_rdf = NULL;
+       uint8_t *salt_data = NULL;
+       
+       ldns_rr_set_rdf(rr, ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8, 1, (void*)&algorithm), 0);
+       ldns_rr_set_rdf(rr, ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT8, 1, (void*)&flags), 1);
+       ldns_rr_set_rdf(rr, ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16, iterations), 2);
+       
+       salt_data = LDNS_XMALLOC(uint8_t, salt_length + 1);
+       salt_data[0] = salt_length;
+       memcpy(salt_data + 1, salt, salt_length);
+       salt_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC3_SALT, salt_length + 1, salt_data);
+       ldns_rr_set_rdf(rr,  salt_rdf, 3);
 
-       while (i < ldns_rdf_size(nsec_bitmap)) {
-               if (bitmap[i] == window_block_nr) {
-                       /* this is the right window, check the bit */
-                       if ((uint8_t) (type / 8) < bitmap[i + 1] &&
-                               ldns_get_bit(&bitmap[i + 1 + (type / 8)], (size_t) (7 - (type % 8)))) {
-                               return true;
-                       } else {
-                               return false;
+       ldns_rr_set_rdf(rr, salt_rdf, 3);
+}
+
+/* this will NOT return the NSEC3  completed, you will have to run the
+   finalize function on the rrlist later! */
+ldns_rr *
+ldns_create_nsec3(ldns_rdf *cur_owner,
+                  ldns_rdf *cur_zone,
+                  ldns_rr_list *rrs,
+                  uint8_t algorithm,
+                  uint8_t flags,
+                  uint16_t iterations,
+                  uint8_t salt_length,
+                  uint8_t *salt,
+                  bool emptynonterminal)
+{
+       size_t i;
+       ldns_rr *i_rr;
+
+       uint8_t *bitmap = LDNS_XMALLOC(uint8_t, 1);
+       uint16_t bm_len = 0;
+       uint16_t i_type;
+
+       ldns_rr *nsec = NULL;
+       ldns_rdf *hashed_owner = NULL;
+       
+       uint8_t *data = NULL;
+       uint8_t cur_data[32];
+       uint8_t cur_window = 0;
+       uint8_t cur_window_max = 0;
+       uint16_t cur_data_size = 0;
+
+       ldns_status status;
+       
+        /*
+        printf("HASH FOR: ");
+        ldns_rdf_print(stdout, cur_owner);
+        */
+       
+       /*
+       printf("\n");
+       for (i=0; i<hashed_owner_str_len; i++) {
+               printf("%02x ", (uint8_t) hashed_owner_str[i]);
+       }
+       printf("\n");
+       */
+       hashed_owner = ldns_nsec3_hash_name(cur_owner, algorithm, iterations, salt_length, salt);
+       status = ldns_dname_cat(hashed_owner, cur_zone);
+       
+       nsec = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3);
+       ldns_rr_set_type(nsec, LDNS_RR_TYPE_NSEC3);
+       ldns_rr_set_owner(nsec, hashed_owner);
+       /* TODO: TTL? */
+       
+       ldns_nsec3_add_param_rdfs(nsec, algorithm, flags, iterations, salt_length, salt);
+       ldns_rr_set_rdf(nsec, NULL, 4);
+
+       bitmap[0] = 0;
+       for (i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
+               i_rr = ldns_rr_list_rr(rrs, i);
+
+               if (ldns_rdf_compare(cur_owner,
+                                    ldns_rr_owner(i_rr)) == 0) {
+                       /* add type to bitmap */
+                       i_type = ldns_rr_get_type(i_rr);
+                       if ((i_type / 8) + 1 > bm_len) {
+                               bitmap = LDNS_XREALLOC(bitmap, uint8_t, (i_type / 8) + 1);
+                               /* set to 0 */
+                               for (; bm_len <= i_type / 8; bm_len++) {
+                                       bitmap[bm_len] = 0;
+                               }
+                       }
+                       ldns_set_bit(bitmap + (int) i_type / 8, (int) (7 - (i_type % 8)), true);
+               }
+       }
+       /* add NSEC and RRSIG anyway */
+       if (!emptynonterminal) {
+               i_type = LDNS_RR_TYPE_RRSIG;
+               if (i_type / 8 > bm_len) {
+                       bitmap = LDNS_XREALLOC(bitmap, uint8_t, (i_type / 8) + 1);
+                       /* set to 0 */
+                       for (; bm_len <= i_type / 8; bm_len++) {
+                               bitmap[bm_len] = 0;
+                       }
+               }
+               ldns_set_bit(bitmap + (int) i_type / 8, (int) (7 - (i_type % 8)), true);
+       }
+
+       /* and SOA if owner == zone */
+       if (ldns_dname_compare(cur_zone, cur_owner) == 0) {
+               i_type = LDNS_RR_TYPE_SOA;
+               if (i_type / 8 > bm_len) {
+                       bitmap = LDNS_XREALLOC(bitmap, uint8_t, (i_type / 8) + 1);
+                       /* set to 0 */
+                       for (; bm_len <= i_type / 8; bm_len++) {
+                               bitmap[bm_len] = 0;
                        }
+               }
+               ldns_set_bit(bitmap + (int) i_type / 8, (int) (7 - (i_type % 8)), true);
+       }
+
+       memset(cur_data, 0, 32);
+       for (i = 0; i < bm_len; i++) {
+               if (i / 32 > cur_window) {
+                       /* check, copy, new */
+                       if (cur_window_max > 0) {
+                               /* this window has stuff, add it */
+                               data = LDNS_XREALLOC(data, uint8_t, cur_data_size + cur_window_max + 3);
+                               data[cur_data_size] = cur_window;
+                               data[cur_data_size + 1] = cur_window_max + 1;
+                               memcpy(data + cur_data_size + 2, cur_data, cur_window_max+1);
+                               cur_data_size += cur_window_max + 3;
+                       }
+                       cur_window++;
+                       cur_window_max = 0;
+                       memset(cur_data, 0, 32);
                } else {
-                       /* this is the wrong window, go to the next */
-                       i++;
-                       i += bitmap[i];
+                       cur_data[i%32] = bitmap[i];
+                       if (bitmap[i] > 0) {
+                               cur_window_max = i%32;
+                       }
                }
        }
+       if (cur_window_max > 0) {
+               /* this window has stuff, add it */
+               data = LDNS_XREALLOC(data, uint8_t, cur_data_size + cur_window_max + 3);
+               data[cur_data_size] = cur_window;
+               data[cur_data_size + 1] = cur_window_max + 1;
+               memcpy(data + cur_data_size + 2, cur_data, cur_window_max+1);
+               cur_data_size += cur_window_max + 3;
+       }
+
+       ldns_rr_set_rdf(nsec, ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC, cur_data_size, data), 5);
+
+       LDNS_FREE(bitmap);
+       LDNS_FREE(data);
+
+/*printf(";; Created NSEC3 for:\n");
+printf(";; ");
+ldns_rdf_print(stdout, cur_owner);
+printf("\n");
+printf(";; ");
+ldns_rr_print(stdout, nsec);
+*/
+       return nsec;
+}
+
+uint8_t
+ldns_nsec3_algorithm(const ldns_rr *nsec3_rr)
+{
+       if (nsec3_rr && ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 &&
+           ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 0)) > 0
+          ) {
+               /*return ldns_rdf_data(ldns_rr_rdf(nsec3_rr, 0))[0];*/
+               return ldns_rdf2native_int8(ldns_rr_rdf(nsec3_rr, 0));
+       }
+       return 0;
+}
+
+uint8_t
+ldns_nsec3_flags(const ldns_rr *nsec3_rr)
+{
+       if (nsec3_rr && ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 &&
+           ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 1)) > 0
+          ) {
+               /*return ldns_rdf_data(ldns_rr_rdf(nsec3_rr, 0))[0];*/
+               return ldns_rdf2native_int8(ldns_rr_rdf(nsec3_rr, 0));
+       }
+       return 0;
+}
+
+bool
+ldns_nsec3_optout(const ldns_rr *nsec3_rr)
+{
+       return (ldns_nsec3_flags(nsec3_rr) & LDNS_NSEC3_VARS_OPTOUT_MASK);
+}
+
+uint16_t
+ldns_nsec3_iterations(const ldns_rr *nsec3_rr)
+{
+       if (nsec3_rr && ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3 &&
+           ldns_rdf_size(ldns_rr_rdf(nsec3_rr, 2)) > 0
+          ) {
+               return ldns_rdf2native_int16(ldns_rr_rdf(nsec3_rr, 2));
+       }
+       return 0;
+       
+}
+
+ldns_rdf
+*ldns_nsec3_salt(const ldns_rr *nsec3_rr)
+{
+       if (nsec3_rr && ldns_rr_get_type(nsec3_rr) == LDNS_RR_TYPE_NSEC3) {
+               return ldns_rr_rdf(nsec3_rr, 3);
+       }
+       return NULL;
+}
+
+uint8_t
+ldns_nsec3_salt_length(const ldns_rr *nsec3_rr)
+{
+       ldns_rdf *salt_rdf = ldns_nsec3_salt(nsec3_rr);
+       if (salt_rdf && ldns_rdf_size(salt_rdf) > 0) {
+               return (uint8_t) ldns_rdf_data(salt_rdf)[0];
+       }
+       return 0;
+}
+
+/* allocs data, free with LDNS_FREE() */
+uint8_t *
+ldns_nsec3_salt_data(const ldns_rr *nsec3_rr)
+{
+       uint8_t salt_length;
+       uint8_t *salt;
+
+       ldns_rdf *salt_rdf = ldns_nsec3_salt(nsec3_rr);
+       if (salt_rdf && ldns_rdf_size(salt_rdf) > 0) {
+               salt_length = ldns_rdf_data(salt_rdf)[0];
+               salt = LDNS_XMALLOC(uint8_t, salt_length);
+               memcpy(salt, &ldns_rdf_data(salt_rdf)[1], salt_length);
+               return salt;
+       }
+       return NULL;
+}
+
+ldns_rdf *
+ldns_nsec3_next_owner(const ldns_rr *nsec3_rr)
+{
+       if (!nsec3_rr || ldns_rr_get_type(nsec3_rr) != LDNS_RR_TYPE_NSEC3) {
+               return NULL;
+       } else {
+               return ldns_rr_rdf(nsec3_rr, 4);
+       }
+}
 
+ldns_rdf *
+ldns_nsec3_bitmap(const ldns_rr *nsec3_rr)
+{
+       if (!nsec3_rr || ldns_rr_get_type(nsec3_rr) != LDNS_RR_TYPE_NSEC3) {
+               return NULL;
+       } else {
+               return ldns_rr_rdf(nsec3_rr, 5);
+       }
+}
+
+ldns_rdf *
+ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, ldns_rdf *name)
+{
+       uint8_t algorithm;
+       uint16_t iterations;
+/*     uint8_t *data;*/
+       uint8_t salt_length;
+       uint8_t *salt = 0;
+/*uint8_t salt_i;*/
+       
+       ldns_rdf *hashed_owner;
+
+/*
+printf("NSEC RDF: ");
+ldns_rdf_print(stdout, ldns_rr_rdf(nsec, 0));
+printf("\n\n");
+*/
+       algorithm = ldns_nsec3_algorithm(nsec);
+       salt_length = ldns_nsec3_salt_length(nsec);
+       salt = ldns_nsec3_salt_data(nsec);
+       iterations = ldns_nsec3_iterations(nsec);
+       
+       hashed_owner = ldns_nsec3_hash_name(name, algorithm, iterations, salt_length, salt);
+       
+/*
+printf(";; Iterations: %u, Salt: ", iterations);
+for (salt_i = 0; salt_i < salt_length; salt_i++) {
+       printf("%02x", salt[salt_i]);
+}
+printf("\n");
+*/
+       LDNS_FREE(salt);
+       return hashed_owner;
+}
+
+bool
+ldns_nsec_bitmap_covers_type(const ldns_rdf *nsec_bitmap, ldns_rr_type type)
+{
+       uint8_t window_block_nr;
+       uint8_t bitmap_length;
+       uint16_t cur_type;
+       uint16_t pos = 0;
+       uint16_t bit_pos;
+       uint8_t *data = ldns_rdf_data(nsec_bitmap);
+       
+       while(pos < ldns_rdf_size(nsec_bitmap)) {
+               window_block_nr = data[pos];
+               bitmap_length = data[pos + 1];
+               pos += 2;
+               
+               for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) {
+                       if (ldns_get_bit(&data[pos], bit_pos)) {
+                               cur_type = 256 * (uint16_t) window_block_nr + bit_pos;
+                               if (cur_type == type) {
+                                       return true;
+                               }
+                       }
+               }
+               
+               pos += (uint16_t) bitmap_length;
+       }
        return false;
 }
 
@@ -1939,15 +2336,51 @@ bool
 ldns_nsec_covers_name(const ldns_rr *nsec, const ldns_rdf *name)
 {
        ldns_rdf *nsec_owner = ldns_rr_owner(nsec);
-       ldns_rdf *nsec_next = ldns_rr_rdf(nsec, 0);
+       ldns_rdf *hash_next;
+       char *next_hash_str;
+       ldns_rdf *nsec_next = NULL;
+       ldns_status status;
+       ldns_rdf *chopped_dname;
+       bool result;
+       
+       if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC) {
+               nsec_next = ldns_rdf_clone(ldns_rr_rdf(nsec, 0));
+       } else if (ldns_rr_get_type(nsec) == LDNS_RR_TYPE_NSEC3) {
+               hash_next = ldns_nsec3_next_owner(nsec);
+               next_hash_str = ldns_rdf2str(hash_next);
+               nsec_next = ldns_dname_new_frm_str(next_hash_str);
+               LDNS_FREE(next_hash_str);
+               chopped_dname = ldns_dname_left_chop(nsec_owner);
+               status = ldns_dname_cat(nsec_next, chopped_dname);
+               ldns_rdf_deep_free(chopped_dname);
+               if (status != LDNS_STATUS_OK) {
+                       printf("error catting: %s\n", ldns_get_errorstr_by_id(status));
+               }
+       } else {
+               ldns_rdf_deep_free(nsec_next);
+               return false;
+       }
        
+/*
+printf("nsec coverage:\n");
+ldns_rdf_print(stdout, nsec_owner);
+printf(" <= \n");
+ldns_rdf_print(stdout, name);
+printf(" <  \n");
+ldns_rdf_print(stdout, nsec_next);
+printf("\n\n");
+*/
        /* in the case of the last nsec */
-       if(ldns_dname_compare(nsec_owner, nsec_next) > 0)
-               return (ldns_dname_compare(nsec_owner, name) <= 0 ||
-                       ldns_dname_compare(name, nsec_next) < 0);
-
-       return (ldns_dname_compare(nsec_owner, name) <= 0 &&
-               ldns_dname_compare(name, nsec_next) < 0);
+       if(ldns_dname_compare(nsec_owner, nsec_next) > 0) {
+               result = (ldns_dname_compare(nsec_owner, name) <= 0 ||
+                         ldns_dname_compare(name, nsec_next) < 0);
+       } else {
+               result = (ldns_dname_compare(nsec_owner, name) <= 0 &&
+                         ldns_dname_compare(name, nsec_next) < 0);
+       }
+       
+       ldns_rdf_deep_free(nsec_next);
+       return result;
 }
 
 /* sig may be null - if so look in the packet */
@@ -2019,7 +2452,7 @@ ldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list)
         * done!
         * ow and don't sign old rrsigs etc.
         */
-        
+       
        ldns_zone *signed_zone;
        ldns_rr_list *cur_rrset;
        ldns_rr_list *cur_rrsigs;
@@ -2042,18 +2475,16 @@ ldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list)
        /* there should only be 1 SOA, so the soa record is 1 rrset */
        cur_rrsigs = NULL;
        ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone)));
-       /*ldns_rr2canonical(ldns_zone_soa(signed_zone));*/
+       ldns_rr2canonical(ldns_zone_soa(signed_zone));
        
        orig_zone_rrs = ldns_rr_list_clone(ldns_zone_rrs(zone));
 
        ldns_rr_list_push_rr(orig_zone_rrs, ldns_rr_clone(ldns_zone_soa(zone)));
        
        /* canon now, needed for correct nsec creation */
-       /*
-       for (i = 0; i < ldns_rr_list_rr_count(orig_zone_rrs); i++) {
+        for (i = 0; i < ldns_rr_list_rr_count(orig_zone_rrs); i++) {
                ldns_rr2canonical(ldns_rr_list_rr(orig_zone_rrs, i));
        }
-       */
        glue_rrs = ldns_zone_glue_rr_list(zone);
 
        /* add the key (TODO: check if it's there already? */
@@ -2100,6 +2531,345 @@ ldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list)
        ldns_rr_list_free(orig_zone_rrs);
        ldns_rr_set_ttl(nsec, ldns_rdf2native_int32(ldns_rr_rdf(ldns_zone_soa(zone), 6)));
 
+       /* Sign all rrsets in the zone */
+       cur_rrset = ldns_rr_list_pop_rrset(signed_zone_rrs);
+       while (cur_rrset) {
+               /* don't sign certain types */
+               cur_rrset_type = ldns_rr_get_type(ldns_rr_list_rr(cur_rrset, 0));
+               cur_dname = ldns_rr_owner(ldns_rr_list_rr(cur_rrset, 0));
+
+               /* if we have KSKs, use them for DNSKEYS, otherwise
+                  make them selfsigned (?) */
+                /* don't sign sigs, delegations, and glue */
+               if (cur_rrset_type != LDNS_RR_TYPE_RRSIG &&
+                   ((ldns_dname_is_subdomain(cur_dname, ldns_rr_owner(ldns_zone_soa(signed_zone)))
+                      && cur_rrset_type != LDNS_RR_TYPE_NS
+                     ) ||
+                    ldns_rdf_compare(cur_dname, ldns_rr_owner(ldns_zone_soa(signed_zone))) == 0
+                   ) &&
+                   !(ldns_rr_list_contains_rr(glue_rrs, ldns_rr_list_rr(cur_rrset, 0)))
+                  ) {
+                       cur_rrsigs = ldns_sign_public(cur_rrset, key_list);
+
+                       /* TODO: make optional, replace exit call */
+                       /* if not optional it should be left out completely
+                          (for it is possible to generate bad signarures, by
+                          specifying a future inception date */
+                       
+                       ldns_zone_push_rr_list(signed_zone, cur_rrset);
+                       ldns_zone_push_rr_list(signed_zone, cur_rrsigs);
+                       ldns_rr_list_free(cur_rrsigs);
+               } else {
+                       /* push it unsigned (glue, sigs, delegations) */
+                       ldns_zone_push_rr_list(signed_zone, cur_rrset);
+               }
+               ldns_rr_list_free(cur_rrset);
+               cur_rrset = ldns_rr_list_pop_rrset(signed_zone_rrs);
+       }
+       ldns_rr_list_deep_free(signed_zone_rrs);
+       ldns_rr_list_deep_free(pubkeys);
+       ldns_rr_list_free(glue_rrs);
+       return signed_zone;
+       
+}
+
+static int
+qsort_rr_compare_nsec3(const void *a, const void *b)
+{
+       const ldns_rr *rr1 = * (const ldns_rr **) a;
+       const ldns_rr *rr2 = * (const ldns_rr **) b;
+       if (rr1 == NULL && rr2 == NULL) {
+               return 0;
+       }
+       if (rr1 == NULL) {
+               return -1;
+       } 
+       if (rr2 == NULL) {
+               return 1;
+       }
+       return ldns_rdf_compare(ldns_rr_owner(rr1), ldns_rr_owner(rr2));
+}
+
+void ldns_rr_list_sort_nsec3(ldns_rr_list *unsorted) {
+       qsort(unsorted->_rrs,
+             ldns_rr_list_rr_count(unsorted),
+             sizeof(ldns_rr *),
+             qsort_rr_compare_nsec3);
+}
+
+ldns_zone *
+ldns_zone_sign_nsec3(ldns_zone *zone, ldns_key_list *key_list, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt)
+{
+       /*
+        * Algorithm to be created:
+        * - sort the rrs (name/class/type?)
+        * - if sorted, every next rr is belongs either to the rrset
+        * you are working on, or the rrset is complete
+        * for each rrset, calculate rrsig and nsec
+        * put the rrset, rrsig and nsec in the new zone
+        * done!
+        * ow and don't sign old rrsigs etc.
+        */
+       
+       ldns_zone *signed_zone;
+       ldns_rr_list *cur_rrset;
+       ldns_rr_list *soa_rrset;
+       ldns_rr_list *cur_rrsigs;
+       ldns_rr_list *orig_zone_rrs;
+       ldns_rr_list *signed_zone_rrs;
+       ldns_rr_list *pubkeys;
+       ldns_rr_list *glue_rrs;
+       ldns_rr_list *nsec3_rrs;
+       ldns_rr *nsec3params;
+       
+       ldns_status status;
+       
+       ldns_rdf *start_dname = NULL;
+       ldns_rdf *cur_dname = NULL;
+       ldns_rr *next_rr = NULL;
+       ldns_rdf *next_dname = NULL;
+       char *next_nsec_owner_str = NULL;
+       ldns_rdf *next_nsec_rdf = NULL;
+       ldns_rr *nsec;
+       ldns_rr *ckey;
+       uint16_t i;
+       uint16_t next_label_count;
+       uint16_t cur_label_count;
+
+       /* for the empty nonterminal finding algorithm */
+       uint16_t j;
+       ldns_rdf *l1, *l2, *post, *post2;
+       bool found_difference;
+       
+       ldns_rr_type cur_rrset_type;
+       
+       signed_zone = ldns_zone_new();
+
+       /* there should only be 1 SOA, so the soa record is 1 rrset */
+       cur_rrsigs = NULL;
+       ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone)));
+       /*ldns_rr2canonical(ldns_zone_soa(signed_zone));*/
+       
+       orig_zone_rrs = ldns_rr_list_clone(ldns_zone_rrs(zone));
+
+       ldns_rr_list_push_rr(orig_zone_rrs, ldns_rr_clone(ldns_zone_soa(zone)));
+       
+       /* canon now, needed for correct nsec creation */
+       /*
+       for (i = 0; i < ldns_rr_list_rr_count(orig_zone_rrs); i++) {
+               ldns_rr2canonical(ldns_rr_list_rr(orig_zone_rrs, i));
+       }
+       */
+       glue_rrs = ldns_zone_glue_rr_list(zone);
+
+       /* create and add the nsec3params rr */
+       nsec3params = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS);
+       ldns_rr_set_owner(nsec3params, ldns_rdf_clone(ldns_rr_owner(ldns_zone_soa(signed_zone))));
+       ldns_nsec3_add_param_rdfs(nsec3params, algorithm, flags, iterations, salt_length, salt);
+/*     ldns_rdf_set_type(ldns_rr_rdf(nsec3params, 0), LDNS_RDF_TYPE_NSEC3_PARAMS_VARS);*/
+       ldns_rr_list_push_rr(orig_zone_rrs, nsec3params);
+/*
+ldns_rr_print(stdout, nsec3params);
+exit(0);
+*/
+       /* add the key (TODO: check if it's there already? */
+       pubkeys = ldns_rr_list_new();
+       for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
+               ckey = ldns_key2rr(ldns_key_list_key(key_list, i));
+               ldns_rr_list_push_rr(pubkeys, ckey);
+       }
+
+       signed_zone_rrs = ldns_rr_list_new();
+       
+       ldns_rr_list_sort(orig_zone_rrs);
+       
+       nsec3_rrs = ldns_rr_list_new();
+       
+       /* add nsecs */
+       for (i = 0; i < ldns_rr_list_rr_count(orig_zone_rrs); i++) {
+               if (!start_dname) {
+                       /*start_dname = ldns_rr_owner(ldns_zone_soa(zone));*/
+                       start_dname = ldns_rr_owner(ldns_rr_list_rr(orig_zone_rrs, i));
+                       cur_dname = start_dname;
+               } else {
+
+                       next_rr = ldns_rr_list_rr(orig_zone_rrs, i);
+                       next_dname = ldns_rr_owner(next_rr);
+                       if (ldns_rdf_compare(cur_dname, next_dname) != 0) {
+
+                               /* every ownername should have an nsec3, and every empty nonterminal */
+                               /* the zone is sorted, so nonterminals should be visible? */
+                               /* if labels after first differ with previous it's an empty nonterm? */
+
+                               /* empty non-terminal detection algorithm 0.001a-pre1
+                                * walk backwards to the first different label. for each label that
+                                * is not the first label, we have found an empty nonterminal
+                                */
+                               cur_label_count = ldns_dname_label_count(cur_dname);
+                               next_label_count = ldns_dname_label_count(next_dname);
+                               post = ldns_dname_new_frm_str(".");
+                               found_difference = false;
+                               for (j = 1; j <= cur_label_count && j <= next_label_count && !found_difference; j++) {
+                                       l1 = ldns_dname_label(cur_dname, cur_label_count - j);
+                                       l2 = ldns_dname_label(next_dname, next_label_count - j);
+                                       
+                                       post2 = ldns_dname_cat_clone(l2, post);
+                                       ldns_rdf_deep_free(post);
+                                       post = post2;
+
+                                       if (ldns_dname_compare(l1, l2) != 0 &&
+                                           /*j < cur_label_count &&*/
+                                           j < next_label_count
+                                          ) {
+                                               /*
+                                               printf("Found empty non-terminal: ");
+                                               ldns_rdf_print(stdout, post);
+                                               printf("\n");
+                                               */
+                                               found_difference = true;
+                                               nsec = ldns_create_nsec3(post, 
+                                                                       ldns_rr_owner(ldns_zone_soa(zone)),
+                                                                       orig_zone_rrs,
+                                                                       algorithm,
+                                                                       false,
+                                                                       iterations,
+                                                                       salt_length,
+                                                                       salt,
+                                                                       true);
+                                               
+                                               printf("Created NSEC3 for: ");
+                                               ldns_rdf_print(stdout, post);
+                                               printf(":\n");
+                                               ldns_rr_print(stdout, nsec);
+                                               
+                                               ldns_rr_set_ttl(nsec, ldns_rdf2native_int32(ldns_rr_rdf(ldns_zone_soa(zone), 6)));
+                                               ldns_rr_list_push_rr(nsec3_rrs, nsec);
+                                       }
+                                       ldns_rdf_deep_free(l1);
+                                       ldns_rdf_deep_free(l2);
+                               }
+                               /* and if next label is longer than cur + 1, these must be empty nons too */
+                               /* skip current label (total now equal to cur_dname) */
+                               if (!found_difference && j < cur_label_count && j < next_label_count) {
+                                       l2 = ldns_dname_label(next_dname, next_label_count - j);
+                                       post2 = ldns_dname_cat_clone(l2, post);
+                                       ldns_rdf_deep_free(post);
+                                       post = post2;
+                                       j++;
+                               }
+                               while (j < next_label_count) {
+                                       l2 = ldns_dname_label(next_dname, next_label_count - j);
+                                       post2 = ldns_dname_cat_clone(l2, post);
+                                       ldns_rdf_deep_free(post);
+                                       post = post2;
+                                       /*
+                                       printf("Found empty non-terminal: ");
+                                       ldns_rdf_print(stdout, post);
+                                       printf("\n");
+                                       */
+                                       ldns_rdf_deep_free(l2);
+                                       j++;    
+                                       nsec = ldns_create_nsec3(post, 
+                                                               ldns_rr_owner(ldns_zone_soa(zone)),
+                                                               orig_zone_rrs,
+                                                               algorithm,
+                                                               false,
+                                                               iterations,
+                                                               salt_length,
+                                                               salt,
+                                                               true);
+/*
+                                       printf("Created NSEC3 for: ");
+                                       ldns_rdf_print(stdout, post);
+                                       printf(":\n");
+                                       ldns_rr_print(stdout, nsec);
+*/
+                                       ldns_rr_set_ttl(nsec, ldns_rdf2native_int32(ldns_rr_rdf(ldns_zone_soa(zone), 6)));
+                                       ldns_rr_list_push_rr(nsec3_rrs, nsec);
+                               }
+                               ldns_rdf_deep_free(post);
+
+                               /* skip glue */
+                               if (ldns_rr_list_contains_rr(glue_rrs, next_rr)) {
+/*                                     cur_dname = next_dname;*/
+                                       printf("Skip glue: ");
+                                       ldns_rdf_print(stdout, cur_dname);
+                                       printf("\n");
+                               } else {
+                                       nsec = ldns_create_nsec3(cur_dname, 
+                                                               ldns_rr_owner(ldns_zone_soa(zone)),
+                                                               orig_zone_rrs,
+                                                               algorithm,
+                                                               false,
+                                                               iterations,
+                                                               salt_length,
+                                                               salt,
+                                                               false);
+
+/*
+                                       printf("Created NSEC3 for: ");
+                                       ldns_rdf_print(stdout, cur_dname);
+                                       printf(":\n");
+                                       ldns_rr_print(stdout, nsec);
+*/
+                                       ldns_rr_set_ttl(nsec, ldns_rdf2native_int32(ldns_rr_rdf(ldns_zone_soa(zone), 6)));
+                                       ldns_rr_list_push_rr(nsec3_rrs, nsec);
+                                       /*start_dname = next_dname;*/
+                                       cur_dname = next_dname;
+                               }
+                       }
+               }
+               ldns_rr_list_push_rr(signed_zone_rrs, ldns_rr_list_rr(orig_zone_rrs, i));
+       }
+       nsec = ldns_create_nsec3(cur_dname, 
+                               ldns_rr_owner(ldns_zone_soa(zone)),
+                               orig_zone_rrs,
+                               algorithm,
+                               false,
+                               iterations,
+                               salt_length,
+                               salt,
+                               false);
+       ldns_rr_list_set_rr(nsec3_rrs, nsec, 4);
+       ldns_rr_list_free(orig_zone_rrs);
+       ldns_rr_set_ttl(nsec, ldns_rdf2native_int32(ldns_rr_rdf(ldns_zone_soa(zone), 6)));
+       ldns_rr_list_push_rr(nsec3_rrs, nsec);
+
+       printf("Created NSEC3 for: ");
+       ldns_rdf_print(stdout, cur_dname);
+       printf(":\n");
+       ldns_rr_print(stdout, nsec);
+       /* sort nsec3s separately, set nexts and append to signed zone */
+       ldns_rr_list_sort_nsec3(nsec3_rrs);
+       for (i = 0; i < ldns_rr_list_rr_count(nsec3_rrs); i++) {
+               if (i == ldns_rr_list_rr_count(nsec3_rrs) - 1) {
+                       next_nsec_owner_str = ldns_rdf2str(ldns_dname_label(ldns_rr_owner(ldns_rr_list_rr(nsec3_rrs, 0)), 0));
+                       if (next_nsec_owner_str[strlen(next_nsec_owner_str) - 1] == '.') {
+                               next_nsec_owner_str[strlen(next_nsec_owner_str) - 1] = '\0';
+                       }
+                       status = ldns_str2rdf_b32_ext(&next_nsec_rdf, next_nsec_owner_str);
+                       if (!ldns_rr_set_rdf(ldns_rr_list_rr(nsec3_rrs, i), next_nsec_rdf, 4)) {
+                               /* todo: error */
+                       }
+               } else {
+                       next_nsec_owner_str = ldns_rdf2str(ldns_dname_label(ldns_rr_owner(ldns_rr_list_rr(nsec3_rrs, i + 1)), 0));
+                       if (next_nsec_owner_str[strlen(next_nsec_owner_str) - 1] == '.') {
+                               next_nsec_owner_str[strlen(next_nsec_owner_str) - 1] = '\0';
+                       }
+                       status = ldns_str2rdf_b32_ext(&next_nsec_rdf, next_nsec_owner_str);
+                       if (!ldns_rr_set_rdf(ldns_rr_list_rr(nsec3_rrs, i), next_nsec_rdf, 4)) {
+                               /* todo: error */
+                       }
+               }
+       }
+       
+       ldns_rr_list_cat(signed_zone_rrs, nsec3_rrs);
+/*
+printf("going to sort:\n");
+ldns_rr_list_print(stdout, signed_zone_rrs);
+*/
+       ldns_rr_list_sort(signed_zone_rrs);
+       
        /* Sign all rrsets in the zone */
        cur_rrset = ldns_rr_list_pop_rrset(signed_zone_rrs);
        while (cur_rrset) {
@@ -2118,13 +2888,28 @@ ldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list)
                        ) &&
                        !(ldns_rr_list_contains_rr(glue_rrs, ldns_rr_list_rr(cur_rrset, 0)))
                   ) {
+                       /*
+                       printf("About to sign RRSET:\n");
+                       ldns_rr_list_print(stdout, cur_rrset);
+                       */
                        cur_rrsigs = ldns_sign_public(cur_rrset, key_list);
 
                        /* TODO: make optional, replace exit call */
                        /* if not optional it should be left out completely
                           (for it is possible to generate bad signarures, by
                           specifying a future inception date */
-                       
+/*
+                       result = ldns_verify(cur_rrset, cur_rrsigs, pubkeys, NULL);
+                       if (result != LDNS_STATUS_OK) {
+                               dprintf("%s", "Cannot verify own sig:\n");
+                               dprintf("%s\n", ldns_get_errorstr_by_id(result));
+                               ERR_load_crypto_strings();
+                               ERR_print_errors_fp(stdout);
+                               exit(result);
+                       } else {
+                               printf("VERIFIED\n");
+                       }
+*/
                        ldns_zone_push_rr_list(signed_zone, cur_rrset);
                        ldns_zone_push_rr_list(signed_zone, cur_rrsigs);
                        ldns_rr_list_free(cur_rrsigs);
index 703234bc96873a56f84a429087ff60c3f7ebb1cd..26030034f932efa352588bc89543fb0fe15bf941 100644 (file)
@@ -236,7 +236,6 @@ do_chase(ldns_resolver *res, ldns_rdf *name, ldns_rr_type type, ldns_rr_class c,
 */
        ldns_pkt *pkt;
        ldns_status tree_result;
-       
        ldns_dnssec_data_chain *chain;
        ldns_dnssec_trust_tree *tree;
        
@@ -245,7 +244,6 @@ do_chase(ldns_resolver *res, ldns_rdf *name, ldns_rr_type type, ldns_rr_class c,
 
        ldns_dname2canonical(name);
        
-       
        pkt = ldns_pkt_clone(pkt_o);
        if (!name) {
                mesg("No name to chase");
index 1345bbad1a9c36a29f7efabb84d8aabe456c4af0..a09ebaebc2ca7e71654f0aef4a39cb727f237c76 100644 (file)
@@ -210,3 +210,279 @@ ldns_verify_denial(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_lis
        return result;
 }
 
+/* NSEC3 draft -07 */
+/*return hash name match*/
+ldns_rr *
+ldns_nsec3_exact_match(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s) {
+       uint8_t algorithm;
+       uint32_t iterations;
+       uint8_t salt_length;
+       uint8_t *salt;
+       
+       ldns_rdf *sname, *hashed_sname;
+       
+       size_t nsec_i;
+       ldns_rr *nsec;
+       ldns_rr *result = NULL;
+       
+       ldns_status status;
+       
+       const ldns_rr_descriptor *descriptor;
+       
+       ldns_rdf *zone_name;
+       
+       if (verbosity >= 4) {
+               printf(";; finding exact match for ");
+               descriptor = ldns_rr_descript(qtype);
+               if (descriptor && descriptor->_name) {
+                       printf("%s ", descriptor->_name);
+               } else {
+                       printf("TYPE%d ", qtype);
+               }
+               ldns_rdf_print(stdout, qname);
+               printf("\n");
+       }
+       
+       if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
+               if (verbosity >= 4) {
+                       printf("no qname, nsec3s or list empty\n");
+               }
+               return NULL;
+       }
+
+       nsec = ldns_rr_list_rr(nsec3s, 0);
+       algorithm = ldns_nsec3_algorithm(nsec);
+       salt_length = ldns_nsec3_salt_length(nsec);
+       salt = ldns_nsec3_salt_data(nsec);
+       iterations = ldns_nsec3_iterations(nsec);
+
+       sname = ldns_rdf_clone(qname);
+
+       if (verbosity >= 4) {
+               printf(";; owner name hashes to: ");
+       }
+       hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
+
+       zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
+       status = ldns_dname_cat(hashed_sname, zone_name);
+       
+       if (verbosity >= 4) {
+               ldns_rdf_print(stdout, hashed_sname);
+               printf("\n");
+       }
+
+       for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
+               nsec = ldns_rr_list_rr(nsec3s, nsec_i);
+               
+               /* check values of iterations etc! */
+               
+               /* exact match? */
+               if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
+                       result = nsec;
+                       goto done;
+               }
+               
+       }
+
+done:
+       ldns_rdf_deep_free(zone_name);
+       ldns_rdf_deep_free(sname);
+       ldns_rdf_deep_free(hashed_sname);
+       LDNS_FREE(salt);
+       
+       if (verbosity >= 4) {
+               if (result) {
+                       printf(";; Found.\n");
+               } else {
+                       printf(";; Not foud.\n");
+               }
+       }
+       return result;
+}
+
+/*return the owner name of the closest encloser for name from the list of rrs */
+/* this is NOT the hash, but the original name! */
+ldns_rdf *
+ldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s)
+{
+       /* remember parameters, they must match */
+       uint8_t algorithm;
+       uint32_t iterations;
+       uint8_t salt_length;
+       uint8_t *salt;
+
+       ldns_rdf *sname, *hashed_sname, *tmp;
+       ldns_rr *ce;
+       bool flag;
+       
+       bool exact_match_found;
+       bool in_range_found;
+       
+       ldns_status status;
+       ldns_rdf *zone_name;
+       
+       size_t nsec_i;
+       ldns_rr *nsec;
+       ldns_rdf *result = NULL;
+       
+       if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
+               return NULL;
+       }
+
+       if (verbosity >= 4) {
+               printf(";; finding closest encloser for type %d ", qtype);
+               ldns_rdf_print(stdout, qname);
+               printf("\n");
+       }
+
+       nsec = ldns_rr_list_rr(nsec3s, 0);
+       algorithm = ldns_nsec3_algorithm(nsec);
+       salt_length = ldns_nsec3_salt_length(nsec);
+       salt = ldns_nsec3_salt_data(nsec);
+       iterations = ldns_nsec3_iterations(nsec);
+
+       sname = ldns_rdf_clone(qname);
+
+       ce = NULL;
+       flag = false;
+       
+       zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
+
+       /* algorithm from nsec3-07 8.3 */
+       while (ldns_dname_label_count(sname) > 0) {
+               exact_match_found = false;
+               in_range_found = false;
+               
+               if (verbosity >= 3) {
+                       printf(";; ");
+                       ldns_rdf_print(stdout, sname);
+                       printf(" hashes to: ");
+               }
+               hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
+
+               status = ldns_dname_cat(hashed_sname, zone_name);
+
+               if (verbosity >= 3) {
+                       ldns_rdf_print(stdout, hashed_sname);
+                       printf("\n");
+               }
+
+               for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
+                       nsec = ldns_rr_list_rr(nsec3s, nsec_i);
+                       
+                       /* check values of iterations etc! */
+                       
+                       /* exact match? */
+                       if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
+                               if (verbosity >= 4) {
+                                       printf(";; exact match found\n");
+                               }
+                               exact_match_found = true;
+                       } else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
+                               if (verbosity >= 4) {
+                                       printf(";; in range of an nsec\n");
+                               }
+                               in_range_found = true;
+                       }
+                       
+               }
+               if (!exact_match_found && in_range_found) {
+                       flag = true;
+               } else if (exact_match_found && flag) {
+                       result = ldns_rdf_clone(sname);
+               } else if (exact_match_found && !flag) {
+                       // error!
+                       if (verbosity >= 4) {
+                               printf(";; the closest encloser is the same name (ie. this is an exact match, ie there is no closest encloser)\n");
+                       }
+                       ldns_rdf_deep_free(hashed_sname);
+                       goto done;
+               } else {
+                       flag = false;
+               }
+               
+               ldns_rdf_deep_free(hashed_sname);
+               tmp = sname;
+               sname = ldns_dname_left_chop(sname);
+               ldns_rdf_deep_free(tmp);
+       }
+
+       done:
+       LDNS_FREE(salt);
+       ldns_rdf_deep_free(zone_name);
+       ldns_rdf_deep_free(sname);
+
+       if (!result) {
+               if (verbosity >= 4) {
+                       printf(";; no closest encloser found\n");
+               }
+       }
+       
+       /* todo checks from end of 6.2. here or in caller? */
+       return result;
+}
+
+
+/* special case were there was a wildcard expansion match, the exact match must be disproven */
+ldns_status
+ldns_verify_denial_wildcard(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_list **nsec_rrs, ldns_rr_list **nsec_rr_sigs)
+{
+       ldns_rdf *nsec3_ce = NULL;
+       ldns_rr *nsec3_ex = NULL;
+       ldns_rdf *wildcard_name = NULL;
+       ldns_rdf *nsec3_wc_ce = NULL;
+       ldns_rr *nsec3_wc_ex = NULL;
+       ldns_rdf *chopped_dname = NULL;
+       ldns_rr_list *nsecs;
+       ldns_status result = LDNS_STATUS_ERR;
+
+       nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION);
+       if (nsecs) {
+               wildcard_name = ldns_dname_new_frm_str("*");
+               chopped_dname = ldns_dname_left_chop(name);
+               result = ldns_dname_cat(wildcard_name, chopped_dname);
+               ldns_rdf_deep_free(chopped_dname);
+
+               nsec3_ex = ldns_nsec3_exact_match(name, type, nsecs);
+               nsec3_ce = ldns_nsec3_closest_encloser(name, type, nsecs);
+               nsec3_wc_ce = ldns_nsec3_closest_encloser(wildcard_name, type, nsecs);                          
+               nsec3_wc_ex = ldns_nsec3_exact_match(wildcard_name, type, nsecs);
+               
+               if (nsec3_ex) {
+                       if (verbosity >= 3) {
+                               printf(";; Error, exact match for for name found, but should not exist (draft -07 section 8.8)\n");
+                       }
+                       result = LDNS_STATUS_NSEC3_ERR;
+               } else if (!nsec3_ce) {
+                       if (verbosity >= 3) {
+                               printf(";; Error, closest encloser for exact match missing in wildcard response (draft -07 section 8.8)\n");
+                       }
+                       result = LDNS_STATUS_NSEC3_ERR;
+/*
+               } else if (!nsec3_wc_ex) {
+                       printf(";; Error, no wildcard nsec3 match: ");
+                       ldns_rdf_print(stdout, wildcard_name);
+                       printf(" (draft -07 section 8.8)\n");
+                       result = LDNS_STATUS_NSEC3_ERR;
+*/
+/*             } else if (!nsec */
+               } else {
+                       if (verbosity >= 3) {
+                               printf(";; wilcard expansion proven\n");
+                       }
+                       result = LDNS_STATUS_OK;
+               }
+       } else {
+               if (verbosity >= 3) {
+                       printf(";; Error: no NSEC or NSEC3 records in answer\n");
+               }
+               result = LDNS_STATUS_CRYPTO_NO_RRSIG;
+       }
+       
+       if (nsecs && nsec_rrs && nsec_rr_sigs) {
+               (void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, 0)), LDNS_RR_TYPE_NSEC3, nsec_rrs, nsec_rr_sigs);
+       }
+       return result;
+}
+
+
index ec456eef1b62d86828981a796ef0f26fbc7e2f64..65d5f6bc45228c2fb5b9661f9fa6845964fb447b 100644 (file)
@@ -31,7 +31,7 @@ usage(FILE *stream, const char *progname)
        fprintf(stream, "\t-D\t\tenable DNSSEC (DO bit)\n");
        fprintf(stream, "\t-T\t\ttrace from the root down to <name>\n");
        fprintf(stream, "\t-S\t\tchase signature(s) from <name> to a know key [*]\n");
-       fprintf(stream, "\t-V\t\tverbose mode (once shows question, twice for hexdumps)\n");
+       fprintf(stream, "\t-V <number>\tverbosity (0-5)\n");
        fprintf(stream, "\t-Q\t\tquiet mode (overrules -V)\n");
        fprintf(stream, "\n");
        fprintf(stream, "\t-f file\t\tread packet from file and send it\n");
index 0f5c28c4254a509e37e95b3d1f20de0dfb6431de..b8f5ddbff8d38034d3ea42ba71546c67895b65cd 100644 (file)
@@ -45,6 +45,8 @@ ldns_rr_list *        get_rr(ldns_resolver *res, ldns_rdf *zname, ldns_rr_type t, ldns_
 void           drill_pkt_print(FILE *fd, ldns_resolver *r, ldns_pkt *p);
 void           drill_pkt_print_footer(FILE *fd, ldns_resolver *r, ldns_pkt *p);
 ldns_pkt_type get_dnssec_rr(ldns_pkt *p, ldns_rdf *name, ldns_rr_type t, ldns_rr_list **rrlist, ldns_rr_list **sig);
+ldns_rr *      ldns_nsec3_exact_match(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s);
+ldns_rdf *     ldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s);
 
 /* verifies denial of existence of *name in *pkt (must contain NSEC or NSEC3 records
  * if *nsec_rrs and *nsec_rr_sigs are given, pointers to the relevant nsecs and their signatures are
index 5c1ad21063a1c02dcbbb8a62d39ce0932156cdb1..0457984b1d57ef142bc2b66af6713ef1306272fd 100644 (file)
@@ -619,11 +619,88 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
                                }
                                ldns_rr_list_deep_free(dataset);
                        } else {
-                               mesg("No DS");
+                               status = ldns_verify_denial(p, name, t, &nsec_rrs, &nsec_rr_sigs);
+                               if (status == LDNS_STATUS_OK) {
+                                       /* verify the nsec3 themselves*/
+                                       if (verbosity >= 5) {
+                                               printf("NSEC(3) Records to verify:\n");
+                                               ldns_rr_list_print(stdout, nsec_rrs);
+                                               printf("With signatures:\n");
+                                               ldns_rr_list_print(stdout, nsec_rr_sigs);
+                                               printf("correct keys at %p:\n", correct_key_list);
+                                               ldns_rr_list_print(stdout, correct_key_list);
+/*
+                                               printf("trusted keys at %p:\n", trusted_keys);
+                                               ldns_rr_list_print(stdout, trusted_keys);
+*/                                     }
+                                       
+                                       if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, trusted_keys, NULL)) == LDNS_STATUS_OK) {
+                                               fprintf(stdout, "%s ", TRUST);
+                                               fprintf(stdout, "Existence denied: ");
+                                               ldns_rdf_print(stdout, name);
+                                               if (descriptor && descriptor->_name) {
+                                                       printf(" %s", descriptor->_name);
+                                               } else {
+                                                       printf(" TYPE%u", t);
+                                               }
+                                               fprintf(stdout, "\n");
+                                       } else if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, correct_key_list, NULL)) == LDNS_STATUS_OK) {
+                                               fprintf(stdout, "%s ", SELF);
+                                               fprintf(stdout, "Existence denied: ");
+                                               ldns_rdf_print(stdout, name);
+                                               if (descriptor && descriptor->_name) {
+                                                       printf(" %s", descriptor->_name);
+                                               } else {
+                                                       printf(" TYPE%u", t);
+                                               }
+                                               fprintf(stdout, "\n");
+                                       } else {
+                                               result = 6;
+                                               fprintf(stdout, "%s ", BOGUS);
+                                               printf("Error verifying denial of existence for ");
+                                               ldns_rdf_print(stdout, name);
+                                               printf(" type ");
+                                               if (descriptor && descriptor->_name) {
+                                                       printf("%s", descriptor->_name);
+                                               } else {
+                                                       printf("TYPE%u", t);
+                                               }
+                                               printf(": %s\n", ldns_get_errorstr_by_id(st));
+                                       }
+                                       
+                                       ldns_rr_list_deep_free(nsec_rrs);
+                                       ldns_rr_list_deep_free(nsec_rr_sigs);
+                               } else {
+/*
+*/
+                                       if (status == LDNS_STATUS_CRYPTO_NO_RRSIG) {
+                                               printf("%s ", UNSIGNED);
+                                               printf("No data found for: ");
+                                               ldns_rdf_print(stdout, name);
+                                               printf(" type ");
+                                               if (descriptor && descriptor->_name) {
+                                                       printf("%s", descriptor->_name);
+                                               } else {
+                                                       printf("TYPE%u", t);
+                                               }
+                                               printf("\n");
+                                       } else {
+                                               printf("[B] Unable to verify denial of existence for ");
+                                               ldns_rdf_print(stdout, name);
+                                               printf(" type ");
+                                               if (descriptor && descriptor->_name) {
+                                                       printf("%s", descriptor->_name);
+                                               } else {
+                                                       printf("TYPE%u", t);
+                                               }
+                                               printf("\n");
+                                       }
+                               
+                               }
                        }
                        ldns_pkt_free(p);
                }
-               ds_list = NULL;
+
                new_nss_aaaa = NULL;
                new_nss_a = NULL;
                new_nss = NULL;
@@ -632,11 +709,9 @@ do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
                key_list = NULL;
                ldns_rr_list_deep_free(key_sig_list);
                key_sig_list = NULL;
-               ldns_rr_list_deep_free(ds_list);
                ds_list = NULL;
                ldns_rr_list_deep_free(ds_sig_list);
                ds_sig_list = NULL;
-               puts("");
        }
        printf(";;" SELF " self sig OK; " BOGUS " bogus; " TRUST " trusted\n");
        /* verbose mode?
diff --git a/error.c b/error.c
index cf11d3479ac7765977844b51a0d1d99305b6120f..88007f79c77693b1797170cbc215b6d94b39cc26 100644 (file)
--- a/error.c
+++ b/error.c
@@ -54,6 +54,7 @@ ldns_lookup_table ldns_error_str[] = {
        { LDNS_STATUS_CRYPTO_TSIG_ERR, "Could not create TSIG signature" },
         { LDNS_STATUS_CRYPTO_EXPIRATION_BEFORE_INCEPTION, "DNSSEC signature has expiration date earlier than inception date" },
        { LDNS_STATUS_ENGINE_KEY_NOT_LOADED, "Unable to load private key from engine" },
+        { LDNS_STATUS_NSEC3_ERR, "Error in NSEC3 denial of existence proof" },
        { LDNS_STATUS_RES_NO_NS, "No nameservers defined in the resolver" },
        { LDNS_STATUS_RES_QUERY, "No correct query given to resolver" },
        { LDNS_STATUS_WIRE_INCOMPLETE_HEADER, "header section incomplete" },
@@ -75,6 +76,7 @@ ldns_lookup_table ldns_error_str[] = {
        { LDNS_STATUS_SYNTAX_EMPTY, "Empty line was returned" },
        { LDNS_STATUS_SYNTAX_TTL, "$TTL directive was seen in the zone" },
        { LDNS_STATUS_SYNTAX_ORIGIN, "$ORIGIN directive was seen in the zone" },
+       { LDNS_STATUS_SYNTAX_ITERATIONS_OVERFLOW, "Iterations count for NSEC3 record higher than maximum" },
        { LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR, "Syntax error, value expected" },
        { LDNS_STATUS_SOCKET_ERROR, "Error creating socket" },
        { LDNS_STATUS_DNSSEC_EXISTENCE_DENIED, "Existence denied by NSEC" },
index 3713e84bb58a43171ad24d0e395cd43a4b8dd753..daaaab9e3e020dc37b2eb0187003f4c7c8102d5a 100644 (file)
@@ -38,6 +38,12 @@ usage(FILE *fp, const char *prog) {
        fprintf(fp, "  -k <id>,<int>\tuse key id with algorithm int from engine\n");
        fprintf(fp, "  -K <id>,<int>\tuse key id with algorithm int from engine as KSK\n");
        fprintf(fp, "\t\tif no key is given (but an external one is used through the engine support, it might be necessary to provide the right algorithm number.\n");
+       fprintf(fp, "  -n\t\tuse NSEC3 instead of NSEC.\n");
+       fprintf(fp, "\t\tIf you use NSEC3, you can specify the following extra options:\n");
+       fprintf(fp, "\t\t-a [algorithm] hashing algorithm\n");
+       fprintf(fp, "\t\t-t [number] number of hash iterations\n");
+       fprintf(fp, "\t\t-s [string] salt\n");
+       fprintf(fp, "\n");
        fprintf(fp, "  keys must be specified by their base name: K<name>+<alg>+<id>\n");
        fprintf(fp, "  if the public part of the key is not present in the zone, \n");
        fprintf(fp, "  both a .key and .private file must be present\n");
@@ -141,6 +147,15 @@ main(int argc, char *argv[])
        char *eng_key_id;
        int eng_key_algo;
        
+       bool use_nsec3 = false;
+       
+       uint8_t nsec3_algorithm = 1;
+       uint8_t nsec3_flags = 0;
+       size_t nsec3_iterations_cmd = 1;
+       uint16_t nsec3_iterations = 1;
+       uint8_t nsec3_salt_length = 0;
+       uint8_t *nsec3_salt = NULL;
+       
        /* we need to know the origin before reading ksk's,
         * so keep an array of filenames until we know it
         */
@@ -160,8 +175,11 @@ main(int argc, char *argv[])
 
 /*     OPENSSL_config(NULL);*/
 
-       while ((c = getopt(argc, argv, "e:f:i:lo:vE:ak:K:")) != -1) {
+       while ((c = getopt(argc, argv, "a:e:f:i:k:lno:s:t:v:E:K:")) != -1) {
                switch (c) {
+               case 'a':
+                       nsec3_algorithm = (uint8_t) atoi(optarg);
+                       break;
                case 'e':
                        /* try to parse YYYYMMDD first,
                         * if that doesn't work, it
@@ -215,6 +233,9 @@ main(int argc, char *argv[])
                case 'l':
                        leave_old_dnssec_data = true;
                        break;
+               case 'n':
+                       use_nsec3 = true;
+                       break;
                case 'o':
                        if (ldns_str2rdf_dname(&origin, optarg) != LDNS_STATUS_OK) {
                                fprintf(stderr, "Bad origin, not a correct domain name\n");
@@ -305,6 +326,32 @@ main(int argc, char *argv[])
                        printf("Not implemented yet\n");
                        exit(EXIT_FAILURE);
                        break;
+               case 's':
+                       if (strlen(optarg) % 2 != 0) {
+                                fprintf(stderr, "Salt value is not valid hex data, not a multiple of 2 characters\n");
+                                exit(EXIT_FAILURE);
+                       }
+                       nsec3_salt_length = (uint8_t) strlen(optarg) / 2;
+                       nsec3_salt = LDNS_XMALLOC(uint8_t, nsec3_salt_length);
+                        for (c = 0; c < (int) strlen(optarg); c += 2) {
+                                if (isxdigit(optarg[c]) && isxdigit(optarg[c+1])) {
+                                        nsec3_salt[c/2] = (uint8_t) ldns_hexdigit_to_int(optarg[c]) * 16 +
+                                                          ldns_hexdigit_to_int(optarg[c+1]);
+                                } else {
+                                        fprintf(stderr, "Salt value is not valid hex data.\n");
+                                        exit(EXIT_FAILURE);
+                                }
+                        }
+
+                       break;
+               case 't':
+                       nsec3_iterations_cmd = (size_t) atol(optarg);
+                       if (nsec3_iterations_cmd > LDNS_NSEC3_MAX_ITERATIONS) {
+                         fprintf(stderr, "Iterations count can not exceed %u, quitting\n", LDNS_NSEC3_MAX_ITERATIONS);
+                         exit(EXIT_FAILURE);
+                       }
+                       nsec3_iterations = (uint16_t) nsec3_iterations_cmd;
+                       break;
                default:
                        usage(stderr, prog);
                        exit(EXIT_SUCCESS);
@@ -438,7 +485,6 @@ main(int argc, char *argv[])
                                found:
                                ldns_rr_free(pubkey_gen);
                                ldns_key_list_push_key(keys, key);
-                               exit(0);
 #if 0
  else {
                                        /* apparently the public key is not in the zone
@@ -499,8 +545,18 @@ main(int argc, char *argv[])
                }
        }
                        
-       signed_zone = ldns_zone_sign(orig_zone, keys);
-
+       if (use_nsec3) {
+               signed_zone = ldns_zone_sign_nsec3(orig_zone,
+                                                  keys,
+                                                  nsec3_algorithm,
+                                                  nsec3_flags,
+                                                  nsec3_iterations,
+                                                  nsec3_salt_length,
+                                                  nsec3_salt);
+       } else {
+               signed_zone = ldns_zone_sign(orig_zone, keys);
+       }
+       
        if (!outputfile_name) {
                outputfile_name = LDNS_XMALLOC(char, MAX_FILENAME_LEN);
                snprintf(outputfile_name, MAX_FILENAME_LEN, "%s.signed", zonefile_name);
@@ -514,7 +570,9 @@ main(int argc, char *argv[])
                        ldns_zone_print(outputfile, signed_zone);
                        fclose(outputfile);
                }
+/*
                ldns_zone_deep_free(signed_zone); 
+*/
        } else {
                fprintf(stderr, "Error signing zone.");
                exit(EXIT_FAILURE);
diff --git a/examples/nsd-test/nsec3-covers.c b/examples/nsd-test/nsec3-covers.c
new file mode 100644 (file)
index 0000000..1326958
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * nsec3-covers. Parses NSEC3s from drill and shows what is covered.
+ *
+ * Pipe the output of the dig/drill query with NSEC3s to the tool.
+ * It will print which domain names are covered by NSEC3s.
+ *
+ * (c) NLnet Labs, 2005, 2006
+ * See the file LICENSE for the license
+ */
+
+#include "config.h"
+#include <ldns/ldns.h>
+#include <errno.h>
+
+void usage(FILE *output)
+{
+       fprintf(output, "Usage: dig +dnssec <query> | nsec3-covers or\n"
+               "drill -D <query> | nsec3-covers\n");
+}
+
+void abort_ldns_error(const char* str, ldns_status err)
+{
+       fprintf(stderr, "error: %s: %s\n", str, ldns_get_errorstr_by_id(err));
+       exit(1);
+}
+
+char*
+skip_comments_and_query(FILE* in, ldns_rdf ** qname)
+{
+       static char buf[10240];
+       /* read comment lines */
+       while(1) {
+               if(!fgets(buf, sizeof(buf), in))
+                       return 0; /* EOF */
+               printf("%s", buf); /* echo */
+               if(strcmp(buf, "") == 0 || strcmp(buf, "\n") == 0)
+                       continue;
+               if(buf[0] != ';')
+                       break;
+               if(strncmp(buf, ";; QUESTION SECTION:", 20) == 0)
+               {
+                       char *q_rr = buf;
+                       /* read question on next line, ;;s before */
+                       if(!fgets(buf, sizeof(buf), in)) return 0;
+                       while(*q_rr == ';' || *q_rr == ' ' || *q_rr == '\t')
+                               ++q_rr;
+                       printf("Question: %s", q_rr);
+                       *strchr(q_rr, '\t') = 0;
+                       *qname = ldns_dname_new_frm_str(q_rr);
+               }
+       }
+       return buf;
+}
+
+void
+read_in(ldns_rr_list* list, ldns_rdf** qname, FILE *in)
+{
+       char* buf;
+       while((buf=skip_comments_and_query(in, qname)))
+       {
+               /* add rr */
+               ldns_rr *rr=0;
+               ldns_rdf *origin=0, *prev=0;
+               ldns_status err;
+               uint16_t ttl = 3600;
+               if((err=ldns_rr_new_frm_str(&rr, buf, ttl, origin, &prev)) != 
+                       LDNS_STATUS_OK)
+                       abort_ldns_error("read rr", err);
+               ldns_rr_list_push_rr(list, rr);
+       }
+       printf("nsec3-covers: read %d rrs\n", (int)ldns_rr_list_rr_count(list));
+       if(!qname) {
+               printf("Could not read question name\n");
+               exit(1);
+       }
+       printf("nsec3-covers: qname is ");
+       ldns_rdf_print(stdout, *qname);
+       printf("\n");
+}
+
+struct donelist {
+       ldns_rdf* name;
+       struct donelist* next;
+};
+static struct donelist *done = 0;
+
+/* this is a linear speed test (slow for large numbers).
+   but the dig response will be small anyway. */
+int check_done(ldns_rdf *qname)
+{
+       struct donelist* p = done;
+       while(p) {
+               if(ldns_dname_compare(qname, p->name)==0)
+                       return 1;
+               p = p->next;
+       }
+       /* not done yet add to list */
+       p = (struct donelist*)malloc(sizeof(struct donelist));
+       p->name = qname;
+       p->next = done;
+       done = p;
+       return 0;
+}
+
+void
+check_cover(ldns_rr_list *list, ldns_rdf *qname)
+{
+       ldns_status status;
+       size_t i;
+       if(check_done(qname))
+               return;
+       for(i=0; i<ldns_rr_list_rr_count(list); ++i)
+       {
+               ldns_rr* nsec3 = ldns_rr_list_rr(list, i);
+               if(ldns_rr_get_type(nsec3) != LDNS_RR_TYPE_NSEC3) {
+                       /* skip non nsec3 */
+                       continue;
+               }
+               ldns_rdf* hashed = ldns_nsec3_hash_name_frm_nsec3(
+                       nsec3, qname);
+               status = ldns_dname_cat(hashed, ldns_dname_left_chop(
+                       ldns_rr_owner(nsec3)));
+               if(status != LDNS_STATUS_OK)
+                       abort_ldns_error("ldns_dname_cat", status);
+
+               if(ldns_dname_compare(hashed, ldns_rr_owner(nsec3)) == 0) {
+                       ldns_rdf_print(stdout, ldns_rr_owner(nsec3));
+                       printf(" proves ");
+                       ldns_rdf_print(stdout, qname);
+                       printf(" exists.\n");
+               }
+               else if(ldns_nsec_covers_name(nsec3, hashed)) {
+                       ldns_rdf_print(stdout, ldns_rr_owner(nsec3));
+                       printf(" proves ");
+                       ldns_rdf_print(stdout, qname);
+                       printf(" does not exist.\n");
+               }
+               ldns_rdf_free(hashed);
+       }
+}
+
+void
+covertests(ldns_rr_list *list, ldns_rdf *qname)
+{
+       size_t i;
+       ldns_rdf *smaller = qname;
+       ldns_rdf *wcard = ldns_dname_new_frm_str("*");
+       for(i=0; i<ldns_dname_label_count(qname)+1; ++i)
+       {
+               check_cover(list, smaller);
+               ldns_rdf* wcardchild = ldns_dname_cat_clone(wcard, smaller);
+               check_cover(list, wcardchild);
+               smaller = ldns_dname_left_chop(smaller);
+       }
+       /* check covers by weird names */
+       if(0) {
+               check_cover(list, ldns_dname_new_frm_str("x.bar.example."));
+               check_cover(list, ldns_dname_new_frm_str("bar.example."));
+       }
+}
+
+int
+main(int argc, char **argv)
+{
+       size_t i;
+       if(argc != 1) {
+               usage(stderr);
+               return 0;
+       }
+       
+       /* read in */
+       ldns_rr_list *list = ldns_rr_list_new();
+       ldns_rdf *qname = 0;
+       read_in(list, &qname, stdin);
+
+       /* check covers */
+       covertests(list, qname);
+       for(i=0; i<ldns_rr_list_rr_count(list); ++i)
+       {
+               ldns_rr* rr = ldns_rr_list_rr(list, i);
+               if(!ldns_dname_is_subdomain(qname, ldns_rr_owner(rr))) {
+                       covertests(list, ldns_rr_owner(rr));
+               }
+       }
+
+       ldns_rr_list_deep_free(list);
+       return 0;
+}
index de6e5145e69d85405cd2cbad1637dbe6b14c26cb..f5bc4ae53113da3c3ba3c490df5e7dd9c0cf5eb2 100644 (file)
@@ -239,6 +239,19 @@ ldns_rdf2buffer_str_b64(ldns_buffer *output, const ldns_rdf *rdf)
        return ldns_buffer_status(output);
 }      
 
+ldns_status
+ldns_rdf2buffer_str_b32_ext(ldns_buffer *output, const ldns_rdf *rdf)
+{
+       size_t size = b32_ntop_calculate_size(ldns_rdf_size(rdf) - 1);
+       char *b32 = LDNS_XMALLOC(char, size + 1);
+       size = (size_t) b32_ntop_extended_hex(ldns_rdf_data(rdf) + 1, ldns_rdf_size(rdf) - 1, b32, size);
+       if (size > 0) {
+               ldns_buffer_printf(output, "%s", b32);
+       }
+       LDNS_FREE(b32);
+       return ldns_buffer_status(output);
+}      
+
 ldns_status
 ldns_rdf2buffer_str_hex(ldns_buffer *output, const ldns_rdf *rdf)
 {
@@ -257,7 +270,7 @@ ldns_rdf2buffer_str_type(ldns_buffer *output, const ldns_rdf *rdf)
        const ldns_rr_descriptor *descriptor;
 
        descriptor = ldns_rr_descript(data);
-       if (descriptor->_name) {
+       if (descriptor && descriptor->_name) {
                ldns_buffer_printf(output, "%s", descriptor->_name);
        } else {
                ldns_buffer_printf(output, "TYPE%u", data);
@@ -297,15 +310,21 @@ ldns_rdf2buffer_str_cert_alg(ldns_buffer *output, const ldns_rdf *rdf)
 ldns_status
 ldns_rdf2buffer_str_alg(ldns_buffer *output, const ldns_rdf *rdf)
 {
+       /* don't use algorithm mnemonics in the presentation format
+          this kind of got sneaked into the rfc's */
         uint8_t data = ldns_rdf_data(rdf)[0];
+/*
        ldns_lookup_table *lt;
 
        lt = ldns_lookup_by_id(ldns_algorithms, (int) data);
        if (lt) {
                ldns_buffer_printf(output, "%s", lt->name);
        } else {
+*/
                ldns_buffer_printf(output, "%d", data);
+/*
        }
+*/
        return ldns_buffer_status(output);
 }      
 
@@ -481,11 +500,11 @@ ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf)
                                type = 256 * (uint16_t) window_block_nr + bit_pos;
                                descriptor = ldns_rr_descript(type);
 
-                               if (descriptor->_name) {
+                               if (descriptor && descriptor->_name) {
                                        ldns_buffer_printf(output, "%s ", 
                                                        descriptor->_name);
                                } else {
-                                       ldns_buffer_printf(output, "TYPE%d ", type);
+                                       ldns_buffer_printf(output, "TYPE%u ", type);
                                }
                        }
                }
@@ -496,6 +515,32 @@ ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf)
        return ldns_buffer_status(output);
 }
 
+ldns_status
+ldns_rdf2buffer_str_nsec3_salt(ldns_buffer *output, const ldns_rdf *rdf)
+{
+       uint8_t salt_length;
+       uint8_t salt_pos;
+
+       uint8_t *data = ldns_rdf_data(rdf);
+       size_t pos;
+
+       salt_length = data[0];
+       /* todo: length check needed/possible? */
+       /* from now there are variable length entries so remember pos */
+       pos = 1;
+       if (salt_length == 0) {
+               ldns_buffer_printf(output, "- ");
+       } else {
+               for (salt_pos = 0; salt_pos < salt_length; salt_pos++) {
+                       ldns_buffer_printf(output, "%02x", data[1 + salt_pos]);
+                       pos++;
+               }
+               ldns_buffer_printf(output, " ");
+       }
+       
+       return ldns_buffer_status(output);
+}
+
 ldns_status
 ldns_rdf2buffer_str_period(ldns_buffer *output, const ldns_rdf *rdf)
 {
@@ -725,6 +770,9 @@ ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf)
                case LDNS_RDF_TYPE_APL:
                        res = ldns_rdf2buffer_str_apl(buffer, rdf);
                        break;
+               case LDNS_RDF_TYPE_B32_EXT:
+                       res = ldns_rdf2buffer_str_b32_ext(buffer, rdf);
+                       break;
                case LDNS_RDF_TYPE_B64:
                        res = ldns_rdf2buffer_str_b64(buffer, rdf);
                        break;
@@ -734,6 +782,9 @@ ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf)
                case LDNS_RDF_TYPE_NSEC: 
                        res = ldns_rdf2buffer_str_nsec(buffer, rdf);
                        break;
+               case LDNS_RDF_TYPE_NSEC3_SALT:
+                       res = ldns_rdf2buffer_str_nsec3_salt(buffer, rdf);
+                       break;
                case LDNS_RDF_TYPE_TYPE: 
                        res = ldns_rdf2buffer_str_type(buffer, rdf);
                        break;
@@ -771,6 +822,9 @@ ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf)
                case LDNS_RDF_TYPE_INT16_DATA:
                        res = ldns_rdf2buffer_str_int16_data(buffer, rdf);
                        break;
+               case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
+                       res = ldns_rdf2buffer_str_b32_ext(buffer, rdf);
+                       break;
                }
        } else {
                ldns_buffer_printf(buffer, "(null) ");
@@ -814,7 +868,7 @@ ldns_rr2buffer_str(ldns_buffer *output, const ldns_rr *rr)
 
                descriptor = ldns_rr_descript(ldns_rr_get_type(rr));
 
-               if (descriptor->_name) {
+               if (descriptor && descriptor->_name) {
                        ldns_buffer_printf(output, "%s", descriptor->_name);
                } else {
                        /* exceptions for qtype */
@@ -1088,6 +1142,7 @@ ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k)
 #ifdef HAVE_SSL
                switch(ldns_key_algorithm(k)) {
                        case LDNS_SIGN_RSASHA1:
+                       case LDNS_SIGN_RSASHA1_NSEC3:
                        case LDNS_SIGN_RSAMD5:
                                /* copied by looking at dnssec-keygen output */
                                /* header */
@@ -1224,6 +1279,7 @@ ldns_key2buffer_str(ldns_buffer *output, const ldns_key *k)
                                RSA_free(rsa);
                                break;
                        case LDNS_SIGN_DSA:
+                       case LDNS_SIGN_DSA_NSEC3:
                                dsa = ldns_key_dsa_key(k);
                        
                                ldns_buffer_printf(output,"Private-key-format: v1.2\n");
diff --git a/keys.c b/keys.c
index 688970812d76124e188382338f393ffe0c071137..77d6884e5983774af65893f0c37cd32ce6204390 100644 (file)
--- a/keys.c
+++ b/keys.c
@@ -136,9 +136,15 @@ ldns_key_new_frm_fp_l(ldns_key **key, FILE *fp, int *line_nr)
        if (strncmp(d, "3 DSA", 2) == 0) {
                alg = LDNS_SIGN_DSA; 
        }
+       if (strncmp(d, "131 DSA", 4) == 0) {
+               alg = LDNS_DSA_NSEC3; 
+       }
        if (strncmp(d, "5 RSASHA1", 2) == 0) {
                alg = LDNS_SIGN_RSASHA1;
        }
+       if (strncmp(d, "133 RSASHA1", 4) == 0) {
+               alg = LDNS_RSASHA1_NSEC3;
+       }
 
        LDNS_FREE(d);
 
@@ -148,12 +154,14 @@ ldns_key_new_frm_fp_l(ldns_key **key, FILE *fp, int *line_nr)
                        return LDNS_STATUS_SYNTAX_ALG_ERR;
                case LDNS_SIGN_RSAMD5:
                case LDNS_SIGN_RSASHA1:
+               case LDNS_RSASHA1_NSEC3:
                        ldns_key_set_algorithm(k, alg);
                        rsa = ldns_key_new_frm_fp_rsa_l(fp, line_nr);
                        ldns_key_set_rsa_key(k, rsa);
                        RSA_free(rsa);
                        break;
                case LDNS_SIGN_DSA:
+               case LDNS_DSA_NSEC3:
                        ldns_key_set_algorithm(k, alg);
                        dsa = ldns_key_new_frm_fp_dsa_l(fp, line_nr);
                        ldns_key_set_dsa_key(k, dsa);
@@ -412,6 +420,7 @@ ldns_key_new_frm_algorithm(ldns_signing_algorithm alg, uint16_t size)
        switch(alg) {
                case LDNS_SIGN_RSAMD5:
                case LDNS_SIGN_RSASHA1:
+               case LDNS_SIGN_RSASHA1_NSEC3:
                        r = RSA_generate_key((int)size, RSA_3, NULL, NULL);
                        if (RSA_check_key(r) != 1) {
                                return NULL;
@@ -420,6 +429,7 @@ ldns_key_new_frm_algorithm(ldns_signing_algorithm alg, uint16_t size)
                        ldns_key_set_rsa_key(k, r);
                        break;
                case LDNS_SIGN_DSA:
+               case LDNS_SIGN_DSA_NSEC3:
                        d = DSA_generate_parameters((int)size, NULL, 0, NULL, NULL, NULL, NULL);
                        if (!d) {
                                return NULL;
@@ -785,6 +795,13 @@ ldns_key2rr(const ldns_key *k)
                                RSA_free(rsa);
                        }
                        break;
+               case LDNS_RSASHA1_NSEC3:
+                       ldns_rr_push_rdf(pubkey,
+                                       ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, LDNS_RSASHA1_NSEC3));
+                       if (!ldns_key_rsa2bin(bin, ldns_key_rsa_key(k), &size)) {
+                               return NULL;
+                       }
+                       break;
                case LDNS_SIGN_DSA:
                        ldns_rr_push_rdf(pubkey,
                                        ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, LDNS_DSA));
@@ -798,6 +815,13 @@ ldns_key2rr(const ldns_key *k)
                                DSA_free(dsa);
                        }
                        break;
+               case LDNS_DSA_NSEC3:
+                       ldns_rr_push_rdf(pubkey,
+                                       ldns_native2rdf_int8(LDNS_RDF_TYPE_ALG, LDNS_DSA_NSEC3));
+                       if (!ldns_key_dsa2bin(bin, ldns_key_dsa_key(k), &size)) {
+                               return NULL;
+                       }
+                       break;
                case LDNS_SIGN_HMACMD5:
                        /* tja */
                        break;
@@ -825,12 +849,14 @@ ldns_key_deep_free(ldns_key *key)
 /*
        switch(ldns_key_algorithm(key)) {
        case LDNS_SIGN_RSASHA1:
+       case LDNS_SIGN_RSASHA1_NSEC3:
        case LDNS_SIGN_RSAMD5:
                if (ldns_key_rsa_key(key)) {
                        RSA_free(ldns_key_rsa_key(key));
                }
                break;
        case LDNS_SIGN_DSA:
+       case LDNS_SIGN_DSA_NSEC3:
                if (ldns_key_dsa_key(key)) {
                        DSA_free(ldns_key_dsa_key(key));
                }
index 72074c2b9bfe404d0d93733db2389065a56ec51e..7eff9755e40c773b05a22023458bd1dc94a21bdf 100644 (file)
@@ -188,6 +188,8 @@ ldns_status ldns_dnssec_trust_tree_contains_keys(ldns_dnssec_trust_tree *tree, l
 ldns_dnssec_data_chain *ldns_dnssec_build_data_chain(ldns_resolver *res, const uint16_t qflags, const ldns_rr_list *data_set, const ldns_pkt *pkt);
 
 
+#define LDNS_NSEC3_MAX_ITERATIONS 65535
+
 /** 
  * calculates a keytag of a key for use in DNSSEC.
  *
@@ -361,17 +363,106 @@ ldns_rr * ldns_create_nsec(ldns_rdf *cur_owner, ldns_rdf *next_owner, ldns_rr_li
 bool ldns_nsec_bitmap_covers_type(const ldns_rdf *nsec_bitmap, ldns_rr_type type);
 
 /**
- * Checks coverage of NSEC RR name span
+ * Checks coverage of NSEC(3) RR name span
  * Remember that nsec and name must both be in canonical form (ie use
  * \ref ldns_rr2canonical and \ref ldns_dname2canonical prior to calling this
  * function)
  *
  * \param[in] nsec The NSEC RR to check
- * \param[in] name The owner dname to check
+ * \param[in] name The owner dname to check, if the nsec record is a NSEC3 record, this should be the hashed name
  * \return true if the NSEC RR covers the owner name
  */
 bool ldns_nsec_covers_name(const ldns_rr *nsec, const ldns_rdf *name);
 
+/**
+ * Returns the hash algorithm used in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The algorithm identifier, or 0 on error
+ */
+uint8_t ldns_nsec3_algorithm(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns the number of hash iterations used in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The number of iterations
+ */
+uint16_t ldns_nsec3_iterations(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns the salt used in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The salt rdf, or NULL on error
+ */
+ldns_rdf *ldns_nsec3_salt(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns the length of the salt used in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The length of the salt in bytes
+ */
+uint8_t ldns_nsec3_salt_length(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns the salt bytes used in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The salt in bytes, this is alloced, so you need to free it
+ */
+uint8_t *ldns_nsec3_salt_data(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns true if the opt-out flag has been set in the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return true if the RR has type NSEC3 and the opt-out bit has been set, false otherwise
+ */
+bool ldns_nsec3_optout(const ldns_rr *nsec3_rr);
+
+/**
+ * Returns the first label of the next ownername in the NSEC3 chain (ie. without the domain)
+ * \param[in] nsec3_rr The RR to read from
+ * \return The first label of the next owner name in the NSEC3 chain, or NULL on error 
+ */
+ldns_rdf *ldns_nsec3_next_owner(const ldns_rr *nsec3_rr);
+
+/**
+ * Sets all the NSEC3 options. The rr to set them in must be initialized with _new() and
+ * type LDNS_RR_TYPE_NSEC3
+ * \param[in] *rr The RR to set the values in
+ * \param[in] algorithm The NSEC3 hash algorithm 
+ * \param[in] flags The flags field 
+ * \param[in] iterations The number of hash iterations
+ * \param[in] salt_length The length of the salt in bytes 
+ * \param[in] The salt bytes
+ */
+void ldns_nsec3_add_param_rdfs(ldns_rr *rr, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt);
+
+
+/**
+ * Returns the bitmap specifying the covered types of the given NSEC3 RR
+ * \param[in] *nsec3_rr The RR to read from
+ * \return The covered type bitmap rdf
+ */
+ldns_rdf *ldns_nsec3_bitmap(const ldns_rr *nsec3_rr);
+
+/**
+ * Calculates the hashed name using the parameters of the given NSEC3 RR
+ * \param[in] *nsec The RR to use the parameters from
+ * \param[in] *name The owner name to calculate the hash for 
+ * \return The hashed owner name rdf, without the domain name
+ */
+ldns_rdf *ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, ldns_rdf *name);
+
+/**
+ * Calculates the hashed name using the given parameters
+ * \param[in] *name The owner name to calculate the hash for 
+ * \param[in] algorithm The hash algorithm to use
+ * \param[in] iterations The number of hash iterations to use
+ * \param[in] salt_length The length of the salt in bytes
+ * \param[in] salt The salt to use
+ * \return The hashed owner name rdf, without the domain name
+ */
+ldns_rdf *ldns_nsec3_hash_name(ldns_rdf *name, uint8_t algorithm, uint16_t iterations, uint8_t salt_length, uint8_t *salt);
+
+
 /**
  * verify a packet 
  * \param[in] p the packet
@@ -395,7 +486,8 @@ ldns_status ldns_pkt_verify(ldns_pkt *p, ldns_rr_type t, ldns_rdf *o, ldns_rr_li
  * \return the signed zone
  */
 ldns_zone *ldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list);
-
+ldns_zone *ldns_zone_sign_nsec3(ldns_zone *zone, ldns_key_list *key_list, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt);
 /**
  * Initialize the random function. This calls OpenSSL
  * \param[in] fd a file providing entropy data
index 3368a5a9dfad102ab4c43ad41054bb83c53f945f..4adce16677d1fb7cb6b1641142b2b9937d11e3f2 100644 (file)
@@ -35,6 +35,7 @@ enum ldns_enum_status
        LDNS_STATUS_INVALID_IP4,
        LDNS_STATUS_INVALID_IP6,
        LDNS_STATUS_INVALID_STR,
+       LDNS_STATUS_INVALID_B32_EXT,
        LDNS_STATUS_INVALID_B64,
        LDNS_STATUS_INVALID_HEX,
        LDNS_STATUS_INVALID_TIME,
@@ -61,6 +62,7 @@ enum ldns_enum_status
        LDNS_STATUS_CRYPTO_EXPIRATION_BEFORE_INCEPTION,
         LDNS_STATUS_CRYPTO_TYPE_COVERED_ERR,
         LDNS_STATUS_ENGINE_KEY_NOT_LOADED,
+        LDNS_STATUS_NSEC3_ERR,
         LDNS_STATUS_RES_NO_NS,
         LDNS_STATUS_RES_QUERY,
         LDNS_STATUS_WIRE_INCOMPLETE_HEADER,
@@ -81,6 +83,7 @@ enum ldns_enum_status
         LDNS_STATUS_SYNTAX_TTL,
         LDNS_STATUS_SYNTAX_ORIGIN,
         LDNS_STATUS_SYNTAX_EMPTY,
+        LDNS_STATUS_SYNTAX_ITERATIONS_OVERFLOW,
         LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR,
         LDNS_STATUS_SOCKET_ERROR,
         LDNS_STATUS_SYNTAX_ERR,
index f902c1a9150d753828d827320d5d1119485ef2ad..fbf3e4046520b961e7a103814c0a237038f279aa 100644 (file)
@@ -43,6 +43,8 @@ enum ldns_enum_algorithm
         LDNS_DSA                = 3,
         LDNS_ECC                = 4,
         LDNS_RSASHA1            = 5,
+        LDNS_DSA_NSEC3         = 131,
+        LDNS_RSASHA1_NSEC3     = 133,
         LDNS_INDIRECT           = 252,
         LDNS_PRIVATEDNS         = 253,
         LDNS_PRIVATEOID         = 254
@@ -67,6 +69,8 @@ enum ldns_enum_signing_algorithm
        LDNS_SIGN_RSAMD5         = LDNS_RSAMD5,
        LDNS_SIGN_RSASHA1        = LDNS_RSASHA1,
        LDNS_SIGN_DSA            = LDNS_DSA,
+       LDNS_SIGN_RSASHA1_NSEC3  = LDNS_RSASHA1_NSEC3,
+       LDNS_SIGN_DSA_NSEC3      = LDNS_DSA_NSEC3,      
        LDNS_SIGN_HMACMD5        = 150  /* not official! */
 };
 typedef enum ldns_enum_signing_algorithm ldns_signing_algorithm;
index 9ab8029a11985b722214658357922af2d378bc9a..c481ad046ccc72edfd7e948a4527b1daae1549eb 100644 (file)
@@ -32,6 +32,8 @@
 #define LDNS_RDF_SIZE_6BYTES            6
 #define LDNS_RDF_SIZE_16BYTES           16
 
+#define LDNS_NSEC3_VARS_OPTOUT_MASK 0x01
+
 /**
  * The different types of RDATA fields.
  */
@@ -55,6 +57,8 @@ enum ldns_enum_rdf_type
        LDNS_RDF_TYPE_STR,
        /** apl data */
        LDNS_RDF_TYPE_APL,
+       /** b32 string */
+       LDNS_RDF_TYPE_B32_EXT,
        /** b64 string */
        LDNS_RDF_TYPE_B64,
        /** hex string */
@@ -90,7 +94,11 @@ enum ldns_enum_rdf_type
        /** NSAP */
        LDNS_RDF_TYPE_NSAP,
        /** IPSECKEY */
-       LDNS_RDF_TYPE_IPSECKEY
+       LDNS_RDF_TYPE_IPSECKEY,
+       /** nsec3 hash salt */
+       LDNS_RDF_TYPE_NSEC3_SALT,
+       /** nsec3 base32 string (with length byte on wire */
+       LDNS_RDF_TYPE_NSEC3_NEXT_OWNER,
 };
 typedef enum ldns_enum_rdf_type ldns_rdf_type;
 
index bd1bf754762851a71ed8016baa89a531a90d04f1..4986dd7c65ed54153df615a36ca8a137c6484392 100644 (file)
--- a/ldns/rr.h
+++ b/ldns/rr.h
@@ -166,6 +166,8 @@ enum ldns_enum_rr_type
        LDNS_RR_TYPE_NSEC = 47,      
        LDNS_RR_TYPE_DNSKEY = 48,
 
+        /* TODO: No type code yet, assume 50 */
+       /*LDNS_RR_TYPE_NSEC3 = 50,      */
        LDNS_RR_TYPE_UINFO = 100,
        LDNS_RR_TYPE_UID = 101,
        LDNS_RR_TYPE_GID = 102,
@@ -182,6 +184,10 @@ enum ldns_enum_rr_type
        LDNS_RR_TYPE_ANY = 255,
 
        LDNS_RR_TYPE_FIRST = 0,
+       /* nsd patch from ben uses 65324 */
+       LDNS_RR_TYPE_NSEC3 = 65324,
+       LDNS_RR_TYPE_NSEC3PARAMS = 65325,
+
        LDNS_RR_TYPE_LAST  = 65535,
        LDNS_RR_TYPE_COUNT = LDNS_RR_TYPE_LAST - LDNS_RR_TYPE_FIRST + 1
 };
@@ -671,6 +677,7 @@ void ldns_rr_list_sort(ldns_rr_list *unsorted);
  *         +1 if rr2 comes before rr1
  */
 int ldns_rr_compare(const ldns_rr *rr1, const ldns_rr *rr2);
+int ldns_rr_compare_nsec3(const ldns_rr *rr1, const ldns_rr *rr2);
 
 /**
  * compares two rrs, up to the rdata.
index d970c69330aea50f650e6caf301e3203e8660aa8..c6df4b9d7e9cf2c87429e1aef5c4185551599656 100644 (file)
@@ -58,6 +58,20 @@ ldns_status ldns_str2rdf_int32(ldns_rdf **rd, const char *longstr);
  */
 ldns_status ldns_str2rdf_time(ldns_rdf **rd, const char *time);
 
+/* convert string with NSEC3 vars to wireformat) 
+ * \param[in] rd the rdf where to put the data
+ * \param[in] str the string to be converted
+ * return ldns_status
+ */
+ldns_status ldns_str2rdf_nsec3_vars(ldns_rdf **rd, const char *nsec3_vars);
+
+/* convert string with NSEC3 salt to wireformat) 
+ * \param[in] rd the rdf where to put the data
+ * \param[in] str the string to be converted
+ * return ldns_status
+ */
+ldns_status ldns_str2rdf_nsec3_salt(ldns_rdf **rd, const char *nsec3_salt);
+
 /* convert a time period (think TTL's) to wireformat) 
  * \param[in] rd the rdf where to put the data
  * \param[in] str the string to be converted
@@ -105,6 +119,14 @@ ldns_status ldns_str2rdf_apl(ldns_rdf **rd, const char *str);
  */
 ldns_status ldns_str2rdf_b64(ldns_rdf **rd, const char *str);
 
+/**
+ * convert the string with the b32 ext hex data into wireformat
+ * \param[in] rd the rdf where to put the data
+ * \param[in] str the string to be converted
+ * \return ldns_status
+ */
+ldns_status ldns_str2rdf_b32_ext(ldns_rdf **rd, const char *str);
+
 /**
  * convert a hex value into wireformat
  * \param[in] rd the rdf where to put the data
diff --git a/rdata.c b/rdata.c
index 126b210a42dd28ec5e887ac13324aa74828d2eb6..d5c38809183f2231458cc252f7cee8ea2ca6e5ca 100644 (file)
--- a/rdata.c
+++ b/rdata.c
@@ -171,6 +171,7 @@ ldns_rdf *
 ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data)
 {
        ldns_rdf *rdf;
+
        rdf = LDNS_MALLOC(ldns_rdf);
        if (!rdf) {
                return NULL;
@@ -250,6 +251,9 @@ ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str)
        case LDNS_RDF_TYPE_B64:
                status = ldns_str2rdf_b64(&rdf, str);
                break;
+       case LDNS_RDF_TYPE_B32_EXT:
+               status = ldns_str2rdf_b32_ext(&rdf, str);
+               break;
        case LDNS_RDF_TYPE_HEX:
                status = ldns_str2rdf_hex(&rdf, str);
                break;
@@ -292,9 +296,16 @@ ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str)
        case LDNS_RDF_TYPE_NSAP:
                status = ldns_str2rdf_nsap(&rdf, str);
                break;
+       case LDNS_RDF_TYPE_NSEC3_SALT:
+               status = ldns_str2rdf_nsec3_salt(&rdf, str);
+               break;
+       case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
+               status = ldns_str2rdf_b32_ext(&rdf, str);
+               break;
        case LDNS_RDF_TYPE_NONE:
        default:
                /* default default ??? */
+               printf("unknown\n");
                status = LDNS_STATUS_ERR;
                break;
        }
diff --git a/rr.c b/rr.c
index d3b5bd49375c1a57691ddba0a27ec2b7fa3a4569..2cde8c992d740e176e576ce8d9068b568a19a805 100644 (file)
--- a/rr.c
+++ b/rr.c
@@ -16,7 +16,7 @@
 
 #include <errno.h>
 
-#define LDNS_SYNTAX_DATALEN 11
+#define LDNS_SYNTAX_DATALEN 16
 #define LDNS_TTL_DATALEN    21
 #define LDNS_RRLIST_INIT    8
 
@@ -322,18 +322,22 @@ ldns_rr_new_frm_str(ldns_rr **newrr, const char *str, uint32_t default_ttl, ldns
 
        desc = ldns_rr_descript((uint16_t)rr_type);
        ldns_rr_set_type(new, rr_type);
-
-       /* only the rdata remains */
-       r_max = ldns_rr_descriptor_maximum(desc);
-       r_min = ldns_rr_descriptor_minimum(desc);
+       if (desc) {
+               /* only the rdata remains */
+               r_max = ldns_rr_descriptor_maximum(desc);
+               r_min = ldns_rr_descriptor_minimum(desc);
+       } else {
+               r_min = 1;
+               r_max = 1;
+       }
 
        /* depending on the rr_type we need to extract
-        * the rdata differently, e.g. NSEC */
+        * the rdata differently, e.g. NSEC/NSEC3 */
        switch(rr_type) {
                default:
                        done = false;
 
-                       for (r_cnt = 0; !done && r_cnt < ldns_rr_descriptor_maximum(desc)
+                       for (r_cnt = 0; !done && r_cnt < r_max
                                        r_cnt++) {
                                quoted = false;
                                /* if type = B64, the field may contain spaces */
@@ -400,7 +404,11 @@ ldns_rr_new_frm_str(ldns_rr **newrr, const char *str, uint32_t default_ttl, ldns
                                                hex_data_str[cur_hex_data_size] = '\0';
                                                r = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_HEX, hex_data_str);
                                                /* correct the rdf type */
-                                               ldns_rdf_set_type(r, ldns_rr_descriptor_field_type(desc, r_cnt));
+                                               if (desc) {
+                                                       ldns_rdf_set_type(r, ldns_rr_descriptor_field_type(desc, r_cnt));
+                                               } else {
+                                                       ldns_rdf_set_type(r, LDNS_RDF_TYPE_UNKNOWN);
+                                               }
                                                LDNS_FREE(hex_data_str);
                                                ldns_rr_push_rdf(new, r);
                                        } else {
@@ -1202,7 +1210,6 @@ qsort_rr_compare(const void *a, const void *b)
        return ldns_rr_compare(rr1, rr2);
 }
 
-
 int
 qsort_schwartz_rr_compare(const void *a, const void *b)
 {
@@ -1662,8 +1669,25 @@ static const ldns_rdf_type type_rrsig_wireformat[] = {
 static const ldns_rdf_type type_nsec_wireformat[] = {
        LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_NSEC
 };
+/* nsec3 is some vars, followed by same type of data of nsec */
+static const ldns_rdf_type type_nsec3_wireformat[] = {
+/*     LDNS_RDF_TYPE_NSEC3_VARS, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC*/
+       LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_NSEC3_SALT, LDNS_RDF_TYPE_NSEC3_NEXT_OWNER, LDNS_RDF_TYPE_NSEC
+};
+
+static const ldns_rdf_type type_nsec3params_wireformat[] = {
+/*     LDNS_RDF_TYPE_NSEC3_PARAMS_VARS*/
+       LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_NSEC3_SALT
+};
+
 static const ldns_rdf_type type_dnskey_wireformat[] = {
-       LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_ALG, LDNS_RDF_TYPE_B64
+       LDNS_RDF_TYPE_INT16,
+       LDNS_RDF_TYPE_INT8,
+       LDNS_RDF_TYPE_ALG,
+       LDNS_RDF_TYPE_B64
 };
 static const ldns_rdf_type type_tsig_wireformat[] = {
        LDNS_RDF_TYPE_DNAME,
@@ -1981,7 +2005,11 @@ static ldns_rr_descriptor rdata_field_descriptors[] = {
 {LDNS_RR_TYPE_ANY, "TYPE247", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
 {LDNS_RR_TYPE_ANY, "TYPE248", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
 {LDNS_RR_TYPE_ANY, "TYPE249", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
-{LDNS_RR_TYPE_TSIG, "TSIG", 8, 9, type_tsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 1 }
+{LDNS_RR_TYPE_DNSKEY, "DNSKEY", 4, 4, type_dnskey_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+/* TODO: no code yet, assume 50 for now */
+{LDNS_RR_TYPE_TSIG, "TSIG", 8, 9, type_tsig_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NSEC3, "NSEC3", 6, 6, type_nsec3_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+{LDNS_RR_TYPE_NSEC3PARAMS, "NSEC3PARAM", 4, 4, type_nsec3params_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }
 };
 /** \endcond */
 
@@ -1992,30 +2020,50 @@ static ldns_rr_descriptor rdata_field_descriptors[] = {
 #define LDNS_RDATA_FIELD_DESCRIPTORS_COUNT \
        (sizeof(rdata_field_descriptors)/sizeof(rdata_field_descriptors[0]))
 
+/* The first 48 fields are 'common' and can be referenced instantly */
+#define LDNS_RDATA_FIELD_DESCRIPTORS_COMMON 48
+
 const ldns_rr_descriptor *
 ldns_rr_descript(uint16_t type)
 {
-       if (type < LDNS_RDATA_FIELD_DESCRIPTORS_COUNT) {
+       size_t i;
+       
+       if (type < LDNS_RDATA_FIELD_DESCRIPTORS_COMMON) {
                return &rdata_field_descriptors[type];
        } else {
-               return &rdata_field_descriptors[0];
+               for (i = LDNS_RDATA_FIELD_DESCRIPTORS_COMMON;
+                    i < LDNS_RDATA_FIELD_DESCRIPTORS_COUNT;
+                    i++) {
+                       if (rdata_field_descriptors[i]._type == type) {
+                               return &rdata_field_descriptors[i];
+                       }
+               }
+               return NULL;
        }
 }
 
 size_t
 ldns_rr_descriptor_minimum(const ldns_rr_descriptor *descriptor)
 {
-       return descriptor->_minimum;
+       if (descriptor) {
+               return descriptor->_minimum;
+       } else {
+               return 0;
+       }
 }
 
 size_t
 ldns_rr_descriptor_maximum(const ldns_rr_descriptor *descriptor)
 {
-       if (descriptor->_variable != LDNS_RDF_TYPE_NONE) {
-               /* Should really be SIZE_MAX... bad FreeBSD.  */
-               return UINT_MAX;
+       if (descriptor) {
+               if (descriptor->_variable != LDNS_RDF_TYPE_NONE) {
+                       /* Should really be SIZE_MAX... bad FreeBSD.  */
+                       return UINT_MAX;
+               } else {
+                       return descriptor->_maximum;
+               }
        } else {
-               return descriptor->_maximum;
+               return 0;
        }
 }
 
@@ -2047,7 +2095,7 @@ ldns_get_rr_type_by_name(const char *name)
 
        /* Normal types */
        for (i = 0; i < (unsigned int) LDNS_RDATA_FIELD_DESCRIPTORS_COUNT; i++) {
-               desc = ldns_rr_descript(i);
+               desc = &rdata_field_descriptors[i];
                desc_name = desc->_name;
                if(desc_name &&
                   strlen(name) == strlen(desc_name) &&
index 785a5001b44f07c6f80f7c647fd68d013360980b..39a5828580eab45d3c0724b86008db801b623dc7 100644 (file)
@@ -114,6 +114,42 @@ ldns_str2rdf_time(ldns_rdf **rd, const char *time)
        return LDNS_STATUS_INVALID_TIME;
 }
 
+ldns_status
+ldns_str2rdf_nsec3_salt(ldns_rdf **rd, const char *salt_str)
+{
+       uint8_t salt_length;
+       uint8_t c;
+
+       uint8_t *salt;
+       uint8_t *data;
+
+       salt_length = (uint8_t) strlen(salt_str);
+       if (salt_length == 1 && salt_str[0] == '-') {
+               salt_length = 0;
+       } else if (salt_length % 2 != 0) {
+               return LDNS_STATUS_INVALID_HEX;
+       }
+       
+       salt = LDNS_XMALLOC(uint8_t, salt_length / 2);
+       for (c = 0; c < salt_length; c += 2) {
+               if (isxdigit(salt_str[c]) && isxdigit(salt_str[c+1])) {
+                       salt[c/2] = (uint8_t) ldns_hexdigit_to_int(salt_str[c]) * 16 +
+                                         ldns_hexdigit_to_int(salt_str[c+1]);
+               } else {
+                       return LDNS_STATUS_INVALID_HEX;
+               }
+       }
+       salt_length = salt_length / 2;
+       
+       data = LDNS_XMALLOC(uint8_t, 1 + salt_length);
+       data[0] = salt_length;
+       memcpy(&data[1], salt, salt_length);
+       *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC3_SALT, 5 + salt_length, data);
+       LDNS_FREE(data);
+       return LDNS_STATUS_OK;
+
+}
+
 ldns_status
 ldns_str2rdf_period(ldns_rdf **rd,const char *period)
 {
@@ -447,6 +483,29 @@ ldns_str2rdf_b64(ldns_rdf **rd, const char *str)
        return LDNS_STATUS_OK;
 }
 
+ldns_status
+ldns_str2rdf_b32_ext(ldns_rdf **rd, const char *str)
+{
+       uint8_t *buffer;
+       int i;
+       /* first byte contains length of actual b32 data */
+       uint8_t len = b32_pton_calculate_size(strlen(str));
+       buffer = LDNS_XMALLOC(uint8_t, len + 1);
+       buffer[0] = len;
+       
+       i = b32_pton_extended_hex((const char*)str, strlen(str), buffer + 1, 
+                                  b32_ntop_calculate_size(strlen(str)));
+       if (i < 0) {
+               return LDNS_STATUS_INVALID_B32_EXT;
+       } else {
+               *rd = ldns_rdf_new_frm_data(
+                       LDNS_RDF_TYPE_B32_EXT, (uint16_t) i + 1, buffer);
+       }
+       LDNS_FREE(buffer);
+
+       return LDNS_STATUS_OK;
+}
+
 ldns_status
 ldns_str2rdf_hex(ldns_rdf **rd, const char *str)
 {
diff --git a/test/14-unit-tests-base.tpkg b/test/14-unit-tests-base.tpkg
new file mode 100644 (file)
index 0000000..2255dda
Binary files /dev/null and b/test/14-unit-tests-base.tpkg differ
diff --git a/util.c b/util.c
index 0ac4982ed35ae40a59f5b54260e0eb6a45c9a33a..5421f538c1852188f91082ff63836f7764958f80 100644 (file)
--- a/util.c
+++ b/util.c
@@ -44,6 +44,18 @@ xprintf_rr(ldns_rr *rr)
        }
 }
 
+void xprintf_hex(uint8_t *data, size_t len)
+{
+       size_t i;
+       for (i = 0; i < len; i++) {
+               if (i > 0 && i % 20 == 0) {
+                       printf("\t; %u - %u\n", (unsigned int) i - 19, (unsigned int) i);
+               }
+               printf("%02x ", (unsigned int) data[i]);
+       }
+       printf("\n");
+}
+
 ldns_lookup_table *
 ldns_lookup_by_name(ldns_lookup_table *table, const char *name)
 {
index 9c4771932ce69e0e752a61fae5cba81cb840c8bb..006fc77ed0dc6511823de301eef70cc2e3d8f0a5 100644 (file)
@@ -173,7 +173,7 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
        for (rdf_index = 0; 
             rdf_index < ldns_rr_descriptor_maximum(descriptor); rdf_index++) {
                if (*pos >= end) {
-                       break;
+                       break;
                }
                cur_rdf_length = 0;
 
@@ -208,6 +208,7 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
                        cur_rdf_length = LDNS_RDF_SIZE_16BYTES;
                        break;
                case LDNS_RDF_TYPE_STR:
+               case LDNS_RDF_TYPE_NSEC3_SALT:
                        /* len is stored in first byte 
                         * it should be in the rdf too, so just
                         * copy len+1 from this position
@@ -217,6 +218,11 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
                case LDNS_RDF_TYPE_INT16_DATA:
                        cur_rdf_length = (size_t) ldns_read_uint16(&wire[*pos]) + 2;
                        break;
+               case LDNS_RDF_TYPE_B32_EXT:
+               case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
+                       /* length is stored in first byte */
+                       cur_rdf_length = (uint8_t) wire[*pos] + 1;
+                       break;
                case LDNS_RDF_TYPE_APL:
                case LDNS_RDF_TYPE_B64:
                case LDNS_RDF_TYPE_HEX:
@@ -235,6 +241,7 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
                        cur_rdf_length = end - *pos;
                        break;
                }
+
                /* fixed length rdata */
                if (cur_rdf_length > 0) {
                        if (cur_rdf_length + *pos > end) {
@@ -300,7 +307,6 @@ ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max,
        }
        
        *rr_p = rr;
-
        return LDNS_STATUS_OK;
        
 status_error: