]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- xfr-tsig, unit test for tsig_sign_query.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 20 Jun 2025 10:13:51 +0000 (12:13 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 20 Jun 2025 10:13:51 +0000 (12:13 +0200)
testcode/unitmain.c
testcode/unittsig.c
util/tsig.c

index 05920667893efc39457024d370cdd289569f9088..e88313ee77f4d6efd5daa9aac179c3d2df872aa3 100644 (file)
@@ -1333,7 +1333,6 @@ main(int argc, char* argv[])
        if(NSS_NoDB_Init(".") != SECSuccess)
                fatal_exit("could not init NSS");
 #endif /* HAVE_SSL or HAVE_NSS*/
-       tsig_test();
        authzone_test();
        neg_test();
        rnd_test();
@@ -1363,6 +1362,7 @@ main(int argc, char* argv[])
 #ifdef HAVE_NGTCP2
        doq_test();
 #endif /* HAVE_NGTCP2 */
+       tsig_test();
        if(log_get_lock()) {
                lock_basic_destroy((lock_basic_type*)log_get_lock());
        }
index 197623175fe5d833442faecadc90d47ac361ed7c..a352100c7785ad4ad00d20ead08071e14e8df9e4 100644 (file)
 #include "config.h"
 #include "util/tsig.h"
 #include "util/config_file.h"
+#include "util/net_help.h"
 #include "testcode/unitmain.h"
+#include "sldns/parseutil.h"
 #include "sldns/sbuffer.h"
+#include "sldns/wire2str.h"
 #include <ctype.h>
 
 #define xstr(s) str(s)
 #define str(s) #s
 #define SRCDIRSTR xstr(SRCDIR)
 
-/** verbosity for this file */
+/** verbosity for this file, 0 no, 1 print some, 2 print packet dumps */
 static int vtest = 0;
 
 /**
@@ -56,15 +59,28 @@ static int vtest = 0;
  *
  * The tsig test files have this syntax. It is made of lines, lines started
  * with # are a comment. empty lines are ignored.
- * file_algorithm <name>
+ * file-algorithm <name>
  *     The name is like md5, sha1, sha256 and if the algorithm is not
  *     supported at the test run time, the file is skipped, silently.
+ *
  * tsig-key:
  *     the following lines define name:, algorithm: and secret:
  *     and it adds a tsig-key that can be used.
  * del-key <name>
  *     The tsig key is deleted, from the in-memory key table.
  *
+ * packet
+ *     A packet in hex dump, on the following lines. Until 'endpacket'.
+ *     It can be used to sign or verify.
+ * check-packet
+ *     A packet in hex dump, on the following lines. Until 'endpacket'.
+ *     It is compared to the packet buffer, and the test fails if not equal.
+ *
+ * tsig-sign-query <key> <time> <expected result>
+ *     It TSIG signs with key name, at timestamp in secs, and the
+ *     result of the call is compared with the expected result, and
+ *     the test fails if not equal. The result is in the packet buffer.
+ *
  */
 
 /** Clean up first keyword */
@@ -137,7 +153,7 @@ tsig_algo_test(char* algo)
 static void
 handle_file_algorithm(char* line, int* break_file)
 {
-       char* algo = get_arg_on_line(line, "file_algorithm");
+       char* algo = get_arg_on_line(line, "file-algorithm");
        if(!tsig_algo_test(algo)) {
                if(vtest)
                        printf("algorithm not supported\n");
@@ -222,6 +238,229 @@ handle_del_key(char* line, struct tsig_key_table* key_table)
                printf("deleted key %s\n", name);
 }
 
+/** skip whitespace */
+static void
+skip_whites(const char** p)
+{
+       while(1) {
+               while(isspace((unsigned char)**p))
+                       (*p)++;
+               if(**p == ';' || **p == '#') {
+                       /* comment, skip until newline */
+                       while(**p && **p != '\n')
+                               (*p)++;
+                       if(**p == '\n')
+                               (*p)++;
+               } else return;
+       }
+}
+
+/** Read hex part into buffer */
+static int
+read_hex_segment(char* s, struct sldns_buffer* buf)
+{
+       uint8_t val;
+       const char* p = s;
+       while(*p) {
+               skip_whites(&p);
+               if(!*p) break;
+               if(sldns_buffer_position(buf) == sldns_buffer_limit(buf)) {
+                       printf("read hex: buffer too small\n");
+                       return 0;
+               }
+               if(sldns_hexdigit_to_int(*p) == -1) {
+                       printf("read hex: not hex: '%c'\n", *p);
+                       return 0;
+               }
+               val = sldns_hexdigit_to_int(*p++) << 4;
+               skip_whites(&p);
+               if(!*p) {
+                       printf("read hex: expected another, second, hex digit\n");
+                       return 0;
+               }
+               if(sldns_hexdigit_to_int(*p) == -1) {
+                       printf("read hex: not hex: '%c'\n", *p);
+                       return 0;
+               }
+               val |= sldns_hexdigit_to_int(*p++);
+               sldns_buffer_write_u8(buf, (uint8_t)val);
+               skip_whites(&p);
+       }
+       return 1;
+}
+
+/** Read hex packet until 'endpacket' */
+static int
+read_packet_hex(char* line, struct sldns_buffer* buf, FILE* in,
+       const char* fname)
+{
+       char l[1024];
+       char* s;
+       sldns_buffer_clear(buf);
+       if(!read_hex_segment(line, buf)) {
+               printf("Could not read hex %s: %s\n", fname, line);
+               return 0;
+       }
+       while(fgets(l, sizeof(l), in)) {
+               line[sizeof(l)-1]=0;
+               s = get_keyword(l);
+               if(strcmp(s, "endpacket") == 0)
+                       break;
+               if(!read_hex_segment(s, buf)) {
+                       printf("Could not read hex %s: %s\n", fname, s);
+                       return 0;
+               }
+       }
+       sldns_buffer_flip(buf);
+       return 1;
+}
+
+/** Handle the packet */
+static void
+handle_packet(char* line, struct sldns_buffer* pkt, FILE* in,
+       const char* fname)
+{
+       char* arg = get_arg_on_line(line, "packet");
+       if(!read_packet_hex(arg, pkt, in, fname))
+               fatal_exit("Could not read packet");
+       if(vtest >= 2) {
+               char* str = sldns_wire2str_pkt(sldns_buffer_begin(pkt),
+                       sldns_buffer_limit(pkt));
+               if(str)
+                       printf("packet: %s\n", str);
+               else
+                       printf("could not wire2str_pkt\n");
+               free(str);
+       }
+}
+
+/** Handle the check-packet */
+static void
+handle_check_packet(char* line, struct sldns_buffer* pkt, FILE* in,
+       const char* fname)
+{
+       char* arg = get_arg_on_line(line, "check-packet");
+       uint8_t data[65536];
+       sldns_buffer check;
+       sldns_buffer_init_frm_data(&check, data, sizeof(data));
+       if(!read_packet_hex(arg, &check, in, fname))
+               fatal_exit("Could not read check-packet");
+       if(vtest >= 2) {
+               char* str = sldns_wire2str_pkt(sldns_buffer_begin(&check),
+                       sldns_buffer_limit(&check));
+               if(str)
+                       printf("check-packet: %s\n", str);
+               else
+                       printf("could not wire2str_pkt\n");
+               free(str);
+       }
+
+       /* Compare the packet */
+       if(vtest && (sldns_buffer_limit(pkt) != sldns_buffer_limit(&check) ||
+               memcmp(sldns_buffer_begin(pkt), sldns_buffer_begin(&check),
+                       sldns_buffer_limit(pkt)) != 0)) {
+               printf("The packet and check-packet are different\n");
+               if(sldns_buffer_limit(pkt) != sldns_buffer_limit(&check))
+                       printf("Lengths are different %d, %d (check)\n",
+                               (int)sldns_buffer_limit(pkt),
+                               (int)sldns_buffer_limit(&check));
+               else printf("Lengths are the same %d\n",
+                               (int)sldns_buffer_limit(pkt));
+               if(vtest >= 2) {
+                       char pkthex[64*1024*2+10], checkhex[64*1024*2+10];
+                       char *pktstr, *checkstr;
+                       hex_ntop(sldns_buffer_begin(pkt), sldns_buffer_limit(pkt),
+                               pkthex, sizeof(pkthex));
+                       hex_ntop(sldns_buffer_begin(&check), sldns_buffer_limit(&check),
+                               checkhex, sizeof(checkhex));
+                       printf("      packet: %s\n", pkthex);
+                       printf("check-packet: %s\n", checkhex);
+                       pktstr = sldns_wire2str_pkt(sldns_buffer_begin(pkt),
+                               sldns_buffer_limit(pkt));
+                       checkstr = sldns_wire2str_pkt(
+                               sldns_buffer_begin(&check),
+                               sldns_buffer_limit(&check));
+                       if(pktstr)
+                               printf("      packet: %s\n", pktstr);
+                       else
+                               printf("      packet: could not wire2str\n");
+                       if(checkstr)
+                               printf("check-packet: %s\n", checkstr);
+                       else
+                               printf("check-packet: could not wire2str\n");
+                       free(pktstr);
+                       free(checkstr);
+               }
+       }
+       unit_assert(sldns_buffer_limit(pkt) == sldns_buffer_limit(&check) &&
+               memcmp(sldns_buffer_begin(pkt), sldns_buffer_begin(&check),
+               sldns_buffer_limit(pkt)) == 0);
+       if(vtest)
+               printf("check-packet is equal\n");
+}
+
+/** Handle the tsig-sign-query */
+static void
+handle_tsig_sign_query(char* line, struct tsig_key_table* key_table,
+       struct sldns_buffer* pkt)
+{
+       char* arg = get_arg_on_line(line, "tsig-sign-query");
+       char* keyname, *s, *timestr, *expectedstr;
+       int expected_result, ret;
+       uint64_t timepoint;
+       struct tsig_data* tsig;
+       size_t pos;
+
+       keyname = arg;
+       s = arg;
+       s = strchr(s, ' ');
+       if(!s || !*s)
+               fatal_exit("expected arguments for %s", arg);
+       *s++ = 0;
+       while(*s && *s == ' ')
+               s++;
+       timestr = s;
+       s = strchr(s, ' ');
+       if(!s || !*s)
+               fatal_exit("expected arguments for %s", arg);
+       *s++ = 0;
+       while(*s && *s == ' ')
+               s++;
+       expectedstr = s;
+
+       timepoint = (uint64_t)atoll(timestr);
+       if(timepoint == 0 && strcmp(timestr, "0") != 0)
+               fatal_exit("expected time argument for %s", timestr);
+       expected_result = atoi(expectedstr);
+       if(expected_result == 0 && strcmp(expectedstr, "0") != 0)
+               fatal_exit("expected int argument for %s", expectedstr);
+
+       if(vtest)
+               printf("tsig-sign-query with %s %d %d\n", keyname,
+                       (int)timepoint, expected_result);
+
+       tsig = tsig_create_fromstr(key_table, keyname);
+       if(!tsig)
+               fatal_exit("alloc fail or key not found %s", keyname);
+
+       /* Put position at the end of the packet to sign it. */
+       pos = sldns_buffer_limit(pkt);
+       sldns_buffer_clear(pkt);
+       sldns_buffer_set_position(pkt, pos);
+
+       ret = tsig_sign_query(tsig, pkt, key_table, timepoint);
+       sldns_buffer_flip(pkt);
+
+       if(vtest) {
+               if(ret == expected_result)
+                       printf("function ok, %s\n", (ret?"success":"fail"));
+               else
+                       printf("function returned %d, expected result %d\n",
+                               ret, expected_result);
+       }
+       unit_assert(ret == expected_result);
+}
+
 /** Handle one line from the TSIG test file */
 static void
 handle_line(char* line, struct tsig_key_table* key_table,
@@ -231,12 +470,18 @@ handle_line(char* line, struct tsig_key_table* key_table,
        char* s = get_keyword(line);
        if(vtest)
                printf("line: %s\n", s);
-       if(strncmp(s, "file_algorithm", 14) == 0) {
+       if(strncmp(s, "file-algorithm", 14) == 0) {
                handle_file_algorithm(s, break_file);
        } else if(strcmp(s, "tsig-key:") == 0) {
                handle_tsig_key(key_table, in, fname);
        } else if(strncmp(s, "delkey", 6) == 0) {
                handle_del_key(s, key_table);
+       } else if(strncmp(s, "packet", 6) == 0) {
+               handle_packet(s, pkt, in, fname);
+       } else if(strncmp(s, "check-packet", 12) == 0) {
+               handle_check_packet(s, pkt, in, fname);
+       } else if(strncmp(s, "tsig-sign-query", 15) == 0) {
+               handle_tsig_sign_query(s, key_table, pkt);
        } else if(strncmp(s, "#", 1) == 0) {
                /* skip comment */
        } else if(strcmp(s, "") == 0) {
index 18c04a3b4b68d8d46e2606858b04b101e00a983c..b6bec9276e11e41c1c5009de7f609ad0f43ebb82 100644 (file)
@@ -205,7 +205,7 @@ tsig_key_table_del_key_fromstr(struct tsig_key_table* key_table,
        size_t len = sizeof(buf);
        struct tsig_key k, *key;
        rbnode_type* node;
-       if(!sldns_str2wire_dname_buf(name, buf, &len)) {
+       if(sldns_str2wire_dname_buf(name, buf, &len) != 0) {
                log_err("could not parse '%s'", name);
                return;
        }
@@ -655,7 +655,7 @@ tsig_create_fromstr(struct tsig_key_table* key_table, char* name)
 {
        uint8_t buf[LDNS_MAX_DOMAINLEN+1];
        size_t len = sizeof(buf);
-       if(!sldns_str2wire_dname_buf(name, buf, &len)) {
+       if(sldns_str2wire_dname_buf(name, buf, &len) != 0) {
                log_err("could not parse '%s'", name);
                return NULL;
        }
@@ -751,6 +751,7 @@ tsig_sign_query(struct tsig_data* tsig, struct sldns_buffer* pkt,
        tsig->fudge = TSIG_FUDGE_TIME; /* seconds */
        if(sldns_buffer_remaining(pkt) < tsig_reserved_space(tsig)) {
                /* Not enough space in buffer for packet and TSIG. */
+               verbose(VERB_ALGO, "tsig_sign_query: not enough buffer space");
                return 0;
        }
        lock_rw_rdlock(&key_table->lock);
@@ -759,6 +760,7 @@ tsig_sign_query(struct tsig_data* tsig, struct sldns_buffer* pkt,
        if(!key) {
                /* The tsig key has disappeared from the key table. */
                lock_rw_unlock(&key_table->lock);
+               verbose(VERB_ALGO, "tsig_sign_query: key not in table");
                return 0;
        }
 
@@ -776,6 +778,7 @@ tsig_sign_query(struct tsig_data* tsig, struct sldns_buffer* pkt,
                + 2 + tsig->other_len)) {
                /* Buffer is too small */
                lock_rw_unlock(&key_table->lock);
+               verbose(VERB_ALGO, "tsig_sign_query: not enough buffer space");
                return 0;
        }
 
@@ -797,6 +800,7 @@ tsig_sign_query(struct tsig_data* tsig, struct sldns_buffer* pkt,
        if(!tsig_algo_calc(key, pkt, tsig)) {
                /* Failure to calculate digest. */
                lock_rw_unlock(&key_table->lock);
+               verbose(VERB_ALGO, "tsig_sign_query: failed to calculate digest");
                return 0;
        }