+<<<<<<< .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
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 $@
--- /dev/null
+
+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.
+
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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);
+}
+
#define Assert(Cond) if (!(Cond)) abort()
+/* 0000000000111111111122222222223333333333444444444455555555556666
+ 0123456789012345678901234567890123456789012345678901234567890123
+*/
static const char Base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
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)
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);
/* 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:
/* 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;
}
/* 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;
}
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;
}
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)) {
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;
}
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;
}
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;
}
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);
/* 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;
+ }
}
}
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:
}
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);
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) {
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;
}
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 */
* done!
* ow and don't sign old rrsigs etc.
*/
-
+
ldns_zone *signed_zone;
ldns_rr_list *cur_rrset;
ldns_rr_list *cur_rrsigs;
/* 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? */
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) {
) &&
!(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);
*/
ldns_pkt *pkt;
ldns_status tree_result;
-
ldns_dnssec_data_chain *chain;
ldns_dnssec_trust_tree *tree;
ldns_dname2canonical(name);
-
pkt = ldns_pkt_clone(pkt_o);
if (!name) {
mesg("No name to chase");
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;
+}
+
+
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");
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
}
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;
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?
{ 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" },
{ 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" },
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");
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
*/
/* 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
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");
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);
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
}
}
- 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);
ldns_zone_print(outputfile, signed_zone);
fclose(outputfile);
}
+/*
ldns_zone_deep_free(signed_zone);
+*/
} else {
fprintf(stderr, "Error signing zone.");
exit(EXIT_FAILURE);
--- /dev/null
+/*
+ * 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;
+}
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)
{
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);
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);
}
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);
}
}
}
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)
{
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;
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;
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) ");
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 */
#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 */
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");
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);
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);
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;
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;
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));
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;
/*
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));
}
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.
*
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
* \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
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,
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,
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,
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
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;
#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.
*/
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 */
/** 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;
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,
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
};
* +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.
*/
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
*/
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
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;
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;
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;
}
#include <errno.h>
-#define LDNS_SYNTAX_DATALEN 11
+#define LDNS_SYNTAX_DATALEN 16
#define LDNS_TTL_DATALEN 21
#define LDNS_RRLIST_INIT 8
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 */
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 {
return ldns_rr_compare(rr1, rr2);
}
-
int
qsort_schwartz_rr_compare(const void *a, const void *b)
{
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,
{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 */
#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;
}
}
/* 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) &&
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)
{
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)
{
}
}
+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)
{
for (rdf_index = 0;
rdf_index < ldns_rr_descriptor_maximum(descriptor); rdf_index++) {
if (*pos >= end) {
- break;
+ break;
}
cur_rdf_length = 0;
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
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:
cur_rdf_length = end - *pos;
break;
}
+
/* fixed length rdata */
if (cur_rdf_length > 0) {
if (cur_rdf_length + *pos > end) {
}
*rr_p = rr;
-
return LDNS_STATUS_OK;
status_error: