#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;
/**
*
* 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 */
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");
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,
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) {