mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-27 20:24:55 +02:00
- xfr-tsig, tsig_sign_query.
This commit is contained in:
+4
-2
@@ -179,11 +179,12 @@ testcode/unitlruhash.c testcode/unitmain.c testcode/unitmsgparse.c \
|
||||
testcode/unitneg.c testcode/unitregional.c testcode/unitslabhash.c \
|
||||
testcode/unitverify.c testcode/readhex.c testcode/testpkts.c testcode/unitldns.c \
|
||||
testcode/unitecs.c testcode/unitauth.c testcode/unitzonemd.c \
|
||||
testcode/unittcpreuse.c testcode/unitdoq.c testcode/unitinfra.c
|
||||
testcode/unittcpreuse.c testcode/unitdoq.c testcode/unitinfra.c \
|
||||
testcode/unittsig.c
|
||||
UNITTEST_OBJ=unitanchor.lo unitdname.lo unitlruhash.lo unitmain.lo \
|
||||
unitmsgparse.lo unitneg.lo unitregional.lo unitslabhash.lo unitverify.lo \
|
||||
readhex.lo testpkts.lo unitldns.lo unitecs.lo unitauth.lo unitzonemd.lo \
|
||||
unittcpreuse.lo unitdoq.lo unitinfra.lo
|
||||
unittcpreuse.lo unitdoq.lo unitinfra.lo unittsig.lo
|
||||
UNITTEST_OBJ_LINK=$(UNITTEST_OBJ) worker_cb.lo $(COMMON_OBJ) $(SLDNS_OBJ) \
|
||||
$(COMPAT_OBJ)
|
||||
DAEMON_SRC=daemon/acl_list.c daemon/cachedump.c daemon/daemon.c \
|
||||
@@ -1267,6 +1268,7 @@ unitzonemd.lo unitzonemd.o: $(srcdir)/testcode/unitzonemd.c config.h $(srcdir)/u
|
||||
unittcpreuse.lo unittcpreuse.o: $(srcdir)/testcode/unittcpreuse.c config.h $(srcdir)/services/outside_network.h \
|
||||
$(srcdir)/util/random.h
|
||||
unitinfra.lo unitinfra.o: $(srcdir)/testcode/unitinfra.c config.h $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/iterator/iterator.h
|
||||
unittsig.lo unittsig.o: $(srcdir)/testcode/unittsig.c config.h $(srcdir)/util/tsig.h $(srcdir)/testcode/unitmain.h
|
||||
acl_list.lo acl_list.o: $(srcdir)/daemon/acl_list.c config.h $(srcdir)/daemon/acl_list.h \
|
||||
$(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/services/view.h $(srcdir)/util/locks.h \
|
||||
$(srcdir)/util/log.h $(srcdir)/util/regional.h $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h \
|
||||
|
||||
@@ -1333,6 +1333,7 @@ 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();
|
||||
|
||||
@@ -88,5 +88,7 @@ void tcpreuse_test(void);
|
||||
void doq_test(void);
|
||||
/** unit test for infra cache functions */
|
||||
void infra_test(void);
|
||||
/** unit test for tsig functions */
|
||||
void tsig_test(void);
|
||||
|
||||
#endif /* TESTCODE_UNITMAIN_H */
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* testcode/unittsig.c - unit test for TSIG signatures.
|
||||
*
|
||||
* Copyright (c) 2025, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* \file
|
||||
* Unit test for tsig code.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "util/tsig.h"
|
||||
#include "testcode/unitmain.h"
|
||||
|
||||
/** test tsig code */
|
||||
void
|
||||
tsig_test(void)
|
||||
{
|
||||
unit_show_feature("tsig");
|
||||
}
|
||||
+168
@@ -54,6 +54,9 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
/** Fudge time to allow in signed time for TSIG records. In seconds. */
|
||||
#define TSIG_FUDGE_TIME 300
|
||||
|
||||
/**
|
||||
* The list of TSIG algorithms. It has short_name, wireformat_name,
|
||||
* wireformat_name_len, digest, max_digest_size.
|
||||
@@ -613,6 +616,15 @@ tsig_create(struct tsig_key_table* key_table, uint8_t* name, size_t namelen)
|
||||
return NULL;
|
||||
}
|
||||
lock_rw_unlock(&key_table->lock);
|
||||
|
||||
tsig->original_query_id = 0;
|
||||
tsig->klass = LDNS_RR_CLASS_ANY;
|
||||
tsig->ttl = 0;
|
||||
tsig->time_signed = 0;
|
||||
tsig->fudge = TSIG_FUDGE_TIME; /* seconds */
|
||||
tsig->error = 0;
|
||||
tsig->other_len = 0;
|
||||
tsig->other_time = 0;
|
||||
return tsig;
|
||||
}
|
||||
|
||||
@@ -636,3 +648,159 @@ tsig_delete(struct tsig_data* tsig)
|
||||
free(tsig->mac);
|
||||
free(tsig);
|
||||
}
|
||||
|
||||
size_t
|
||||
tsig_reserved_space(struct tsig_data* tsig)
|
||||
{
|
||||
if(!tsig)
|
||||
return 0;
|
||||
return
|
||||
tsig->key_name_len /* Owner */
|
||||
+ sizeof(uint16_t) /* Type */
|
||||
+ sizeof(uint16_t) /* Class */
|
||||
+ sizeof(uint32_t) /* TTL */
|
||||
+ sizeof(uint16_t) /* RDATA length */
|
||||
+ tsig->algorithm_name_len /* Algorithm */
|
||||
+ 6 /* 48bit */ /* Signed time */
|
||||
+ sizeof(uint16_t) /* Fudge */
|
||||
+ sizeof(uint16_t) /* Mac size */
|
||||
+ tsig->mac_size /* Mac data */
|
||||
+ sizeof(uint16_t) /* Original query ID */
|
||||
+ sizeof(uint16_t) /* Error code */
|
||||
+ sizeof(uint16_t) /* Other size */
|
||||
+ 6; /* 48bit in case of Other data */
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the digest for the TSIG algorithm over the packet.
|
||||
* Called must hold locks, on key. This routine performs one-host
|
||||
* calculation.
|
||||
* @param key: the key, and algorithm.
|
||||
* @param pkt: packet with contents.
|
||||
* @param tsig: where to store the result.
|
||||
* @return false on failure.
|
||||
*/
|
||||
static int
|
||||
tsig_algo_calc(struct tsig_key* key, struct sldns_buffer* pkt,
|
||||
struct tsig_data* tsig)
|
||||
{
|
||||
const EVP_MD* evp_md;
|
||||
unsigned int hmac_result_len;
|
||||
unsigned char* hmac_result;
|
||||
|
||||
/* Setup digester algorithm */
|
||||
evp_md = EVP_get_digestbyname(key->algo->digest);
|
||||
if(!evp_md) {
|
||||
/* Could not fetch algorithm. */
|
||||
char name[256], buf[1024];
|
||||
dname_str(key->name, name);
|
||||
snprintf(buf, sizeof(buf), "EVP_get_digestbyname failed for %s %s",
|
||||
name, key->algo->digest);
|
||||
log_crypto_err(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Perform calculation */
|
||||
hmac_result_len = tsig->mac_size;
|
||||
hmac_result = HMAC(evp_md, key->data, key->data_len,
|
||||
sldns_buffer_begin(pkt), sldns_buffer_position(pkt),
|
||||
tsig->mac, &hmac_result_len);
|
||||
if(!hmac_result) {
|
||||
/* The HMAC calculation failed. */
|
||||
char name[256], buf[1024];
|
||||
dname_str(key->name, name);
|
||||
snprintf(buf, sizeof(buf), "HMAC failed for %s %s",
|
||||
name, key->algo->digest);
|
||||
log_crypto_err(buf);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
tsig_sign_query(struct tsig_data* tsig, struct sldns_buffer* pkt,
|
||||
struct tsig_key_table* key_table, uint64_t now)
|
||||
{
|
||||
size_t aftername_pos;
|
||||
struct tsig_key* key;
|
||||
if(!tsig)
|
||||
return 0;
|
||||
tsig->time_signed = now;
|
||||
tsig->fudge = TSIG_FUDGE_TIME; /* seconds */
|
||||
if(sldns_buffer_remaining(pkt) < tsig_reserved_space(tsig)) {
|
||||
/* Not enough space in buffer for packet and TSIG. */
|
||||
return 0;
|
||||
}
|
||||
lock_rw_rdlock(&key_table->lock);
|
||||
key = tsig_key_table_search(key_table, tsig->key_name,
|
||||
tsig->key_name_len);
|
||||
if(!key) {
|
||||
/* The tsig key has disappeared from the key table. */
|
||||
lock_rw_unlock(&key_table->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tsig->original_query_id = sldns_buffer_read_u16_at(pkt, 0);
|
||||
|
||||
/* What is signed is this buffer:
|
||||
* <packet with original query id and ARCOUNT without TSIG>
|
||||
* <name> TSIG owner is key name
|
||||
* u16 class, u32 TTL, <name> algorithm_name, u48 time_signed,
|
||||
* u16 fudge, u16 error, u16 other_len, <data> other_data. */
|
||||
/* That fits in the current buffer, since the reserved space for
|
||||
* the TSIG record is larger. */
|
||||
|
||||
/* Write uncompressed TSIG owner, it is the key name. */
|
||||
sldns_buffer_write(pkt, tsig->key_name, tsig->key_name_len);
|
||||
aftername_pos = sldns_buffer_position(pkt);
|
||||
sldns_buffer_write_u16(pkt, tsig->klass);
|
||||
sldns_buffer_write_u32(pkt, tsig->ttl);
|
||||
sldns_buffer_write(pkt, key->algo->wireformat_name,
|
||||
key->algo->wireformat_name_len);
|
||||
sldns_buffer_write_u48(pkt, tsig->time_signed);
|
||||
sldns_buffer_write_u16(pkt, tsig->fudge);
|
||||
sldns_buffer_write_u16(pkt, tsig->error);
|
||||
sldns_buffer_write_u16(pkt, tsig->other_len);
|
||||
if(tsig->other_len != 0)
|
||||
sldns_buffer_write_u48(pkt, tsig->other_time);
|
||||
|
||||
/* Sign it */
|
||||
if(!tsig_algo_calc(key, pkt, tsig)) {
|
||||
/* Failure to calculate digest. */
|
||||
lock_rw_unlock(&key_table->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Append TSIG record */
|
||||
/* The record appended consists of:
|
||||
* owner name, u16 type, u16 class, u32 TTL, u16 rdlength,
|
||||
* algo name, u48 signed_time, u16 fudge, u16 mac_len, mac data,
|
||||
* u16 original_query_id, u16 error, u16 other_len, other data.
|
||||
*/
|
||||
sldns_buffer_set_position(pkt, aftername_pos);
|
||||
sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TSIG);
|
||||
sldns_buffer_write_u16(pkt, tsig->klass);
|
||||
sldns_buffer_write_u32(pkt, tsig->ttl);
|
||||
|
||||
/* rdlength */
|
||||
sldns_buffer_write_u16(pkt, key->algo->wireformat_name_len
|
||||
+ 6 + 2 + 2 /* time,fudge,maclen */ + tsig->mac_size
|
||||
+ 2 + 2 + 2 /* id,error,otherlen */ + tsig->other_len);
|
||||
sldns_buffer_write(pkt, key->algo->wireformat_name,
|
||||
key->algo->wireformat_name_len);
|
||||
sldns_buffer_write_u48(pkt, tsig->time_signed);
|
||||
sldns_buffer_write_u16(pkt, tsig->fudge);
|
||||
sldns_buffer_write_u16(pkt, tsig->mac_size);
|
||||
sldns_buffer_write(pkt, tsig->mac, tsig->mac_size);
|
||||
sldns_buffer_write_u16(pkt, tsig->original_query_id);
|
||||
sldns_buffer_write_u16(pkt, tsig->error);
|
||||
sldns_buffer_write_u16(pkt, tsig->other_len);
|
||||
if(tsig->other_len == 6)
|
||||
sldns_buffer_write_u48(pkt, tsig->other_time);
|
||||
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(pkt),
|
||||
LDNS_ARCOUNT(sldns_buffer_begin(pkt))+1);
|
||||
|
||||
lock_rw_unlock(&key_table->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
+27
-1
@@ -95,6 +95,22 @@ struct tsig_data {
|
||||
size_t mac_size;
|
||||
/** digest buffer */
|
||||
uint8_t* mac;
|
||||
/** original query ID */
|
||||
uint16_t original_query_id;
|
||||
/** the TSIG class */
|
||||
uint16_t klass;
|
||||
/** the TSIG TTL */
|
||||
uint16_t ttl;
|
||||
/** the time signed, 48bit */
|
||||
uint64_t time_signed;
|
||||
/** fudge amount of time_signed */
|
||||
uint16_t fudge;
|
||||
/** the TSIG error code */
|
||||
uint16_t error;
|
||||
/** other data length, 6 for other_time as failed time. */
|
||||
uint16_t other_len;
|
||||
/** if other len 6, this is 48bit time of error. */
|
||||
uint64_t other_time;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -247,9 +263,12 @@ void tsig_delete(struct tsig_data* tsig);
|
||||
* Sign a query with TSIG. Appends the TSIG record.
|
||||
* @param tsig: the tsig data, keeps state to verify reply.
|
||||
* @param pkt: query packet. position must be at end of packet.
|
||||
* @param key_table: the tsig key table is used to fetch the key details.
|
||||
* @param now: time to sign the query, the current time.
|
||||
* @return false on failure.
|
||||
*/
|
||||
int tsig_sign_query(struct tsig_data* tsig, struct sldns_buffer* pkt);
|
||||
int tsig_sign_query(struct tsig_data* tsig, struct sldns_buffer* pkt,
|
||||
struct tsig_key_table* key_table, uint64_t now);
|
||||
|
||||
/**
|
||||
* Verify a query with TSIG.
|
||||
@@ -308,4 +327,11 @@ int tsig_sign_reply(struct tsig_data* tsig, struct sldns_buffer* pkt);
|
||||
*/
|
||||
int tsig_verify_reply(struct tsig_data* tsig, struct sldns_buffer* pkt);
|
||||
|
||||
/**
|
||||
* Calculate reserved space for TSIG.
|
||||
* @param tsig: the tsig data
|
||||
* @return number of bytes to keep reserved for the TSIG added.
|
||||
*/
|
||||
size_t tsig_reserved_space(struct tsig_data* tsig);
|
||||
|
||||
#endif /* UTIL_TSIG_H */
|
||||
|
||||
Reference in New Issue
Block a user