mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
major TSIG/TKEY cleanup
This commit is contained in:
parent
4380033dc4
commit
b984520acc
9 changed files with 387 additions and 193 deletions
|
|
@ -190,6 +190,7 @@ struct dns_message {
|
|||
ISC_LIST(dns_rdata_t) freerdata;
|
||||
ISC_LIST(dns_rdatalist_t) freerdatalist;
|
||||
|
||||
dns_tsig_keyring_t *ring;
|
||||
dns_rcode_t tsigstatus;
|
||||
dns_rcode_t querytsigstatus;
|
||||
dns_rdata_any_tsig_t *tsig;
|
||||
|
|
@ -272,9 +273,7 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
|
|||
* DNS message.
|
||||
*
|
||||
* OPT records are detected and stored in the pseudo-section "opt".
|
||||
* TSIGs are detected and stored in the pseudo-section "tsig". At detection
|
||||
* time, the TSIG is verified (XXX) and the message fails if the TSIG fails
|
||||
* to verify.
|
||||
* TSIGs are detected and stored in the pseudo-section "tsig".
|
||||
*
|
||||
* If 'preserve_order' is true, or if the opcode of the message is UPDATE,
|
||||
* a separate dns_name_t object will be created for each RR in the message.
|
||||
|
|
@ -887,6 +886,26 @@ dns_message_signer(dns_message_t *msg, dns_name_t *signer);
|
|||
* the signature has not been verified yet
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_message_checksig(dns_message_t *msg, dns_view_t *view);
|
||||
/*
|
||||
* If this message was signed, verify the signature.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* msg is a valid parsed message.
|
||||
* view is a valid view
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* ISC_R_SUCCESS - the message was unsigned, or the message
|
||||
* was signed correctly.
|
||||
*
|
||||
* DNS_R_EXPECTEDTSIG - A TSIG was expected, but not seen
|
||||
* DNS_R_UNEXPECTEDTSIG - A TSIG was seen but not expected
|
||||
* DNS_R_TSIGVERIFYFAILURE - The TSIG failed to verify
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* DNS_MESSAGE_H */
|
||||
|
|
|
|||
|
|
@ -36,15 +36,22 @@ ISC_LANG_BEGINDECLS
|
|||
#define DNS_TKEYMODE_RESOLVERASSIGNED 4
|
||||
#define DNS_TKEYMODE_DELETE 5
|
||||
|
||||
struct dns_tkey_ctx {
|
||||
dst_key_t *dhkey;
|
||||
dns_name_t *domain;
|
||||
isc_mem_t *mctx;
|
||||
};
|
||||
|
||||
isc_result_t
|
||||
dns_tkey_init(isc_log_t *lctx, dns_c_ctx_t *cfg, isc_mem_t *mctx);
|
||||
dns_tkey_init(dns_c_ctx_t *cfg, isc_mem_t *mctx, dns_tkey_ctx_t **tctx);
|
||||
/*
|
||||
* Obtains TKEY configuration information, including default DH key
|
||||
* and default domain from the configuration, if it's not NULL.
|
||||
*
|
||||
* Requires:
|
||||
* 'lctx' is not NULL
|
||||
* 'mctx' is not NULL
|
||||
* 'tctx' is not NULL
|
||||
* '*tctx' is NULL
|
||||
*
|
||||
* Returns
|
||||
* ISC_R_SUCCESS
|
||||
|
|
@ -53,19 +60,26 @@ dns_tkey_init(isc_log_t *lctx, dns_c_ctx_t *cfg, isc_mem_t *mctx);
|
|||
*/
|
||||
|
||||
void
|
||||
dns_tkey_destroy(void);
|
||||
dns_tkey_destroy(dns_tkey_ctx_t **tctx);
|
||||
/*
|
||||
* Frees all data associated with the TKEY subsystem
|
||||
* Frees all data associated with the TKEY context
|
||||
*
|
||||
* Requires:
|
||||
* 'tctx' is not NULL
|
||||
* '*tctx' is not NULL
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_tkey_processquery(dns_message_t *msg);
|
||||
dns_tkey_processquery(dns_message_t *msg, dns_tkey_ctx_t *tctx,
|
||||
dns_tsig_keyring_t *ring);
|
||||
/*
|
||||
* Processes a query containing a TKEY record, adding or deleting TSIG
|
||||
* keys if necessary, and modifies the message to contain the response.
|
||||
*
|
||||
* Requires:
|
||||
* 'msg' is a valid message
|
||||
* 'tctx' is a valid TKEY context
|
||||
* 'ring' is a valid TSIG keyring
|
||||
*
|
||||
* Returns
|
||||
* ISC_R_SUCCESS msg was updated (the TKEY operation succeeded,
|
||||
|
|
@ -117,7 +131,8 @@ dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key);
|
|||
|
||||
isc_result_t
|
||||
dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
|
||||
dst_key_t *key, dns_tsigkey_t **outkey);
|
||||
dst_key_t *key, isc_buffer_t *nonce,
|
||||
dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring);
|
||||
/*
|
||||
* Processes a response to a query containing a TKEY that was
|
||||
* designed to generate a shared secret using a Diffie-Hellman key
|
||||
|
|
@ -129,6 +144,7 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
|
|||
* 'rmsg' is a valid message (the response)
|
||||
* 'key' is a valid Diffie Hellman dst key
|
||||
* 'outkey' is either NULL or a pointer to NULL
|
||||
* 'ring' is not NULL
|
||||
*
|
||||
* Returns:
|
||||
* ISC_R_SUCCESS the shared key was successfully added
|
||||
|
|
@ -137,7 +153,8 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
|
|||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg);
|
||||
dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
|
||||
dns_tsig_keyring_t *ring);
|
||||
/*
|
||||
* Processes a response to a query containing a TKEY that was
|
||||
* designed to delete a shared secret. If the query was successful,
|
||||
|
|
@ -146,6 +163,7 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg);
|
|||
* Requires:
|
||||
* 'qmsg' is a valid message (the query)
|
||||
* 'rmsg' is a valid message (the response)
|
||||
* 'ring' is not NULL
|
||||
*
|
||||
* Returns:
|
||||
* ISC_R_SUCCESS the shared key was successfully deleted
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include <isc/types.h>
|
||||
#include <isc/lang.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/rwlock.h>
|
||||
|
||||
#include <dns/types.h>
|
||||
#include <dns/name.h>
|
||||
|
|
@ -38,6 +38,12 @@ extern dns_name_t *dns_tsig_hmacmd5_name;
|
|||
/* Default fudge value. */
|
||||
#define DNS_TSIG_FUDGE 300
|
||||
|
||||
struct dns_tsig_keyring {
|
||||
ISC_LIST(dns_tsigkey_t) keys;
|
||||
isc_rwlock_t lock;
|
||||
isc_mem_t *mctx;
|
||||
};
|
||||
|
||||
struct dns_tsigkey {
|
||||
/* Unlocked */
|
||||
unsigned int magic; /* Magic number. */
|
||||
|
|
@ -62,10 +68,11 @@ struct dns_tsigkey {
|
|||
isc_result_t
|
||||
dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
|
||||
unsigned char *secret, int length, isc_boolean_t generated,
|
||||
dns_name_t *creator, isc_mem_t *mctx, dns_tsigkey_t **key);
|
||||
dns_name_t *creator, isc_mem_t *mctx,
|
||||
dns_tsig_keyring_t *ring, dns_tsigkey_t **key);
|
||||
/*
|
||||
* Creates and saves a tsig key structure. If key is not NULL, *key
|
||||
* will contain a copy of the key.
|
||||
* Creates a tsig key structure and saves it in the keyring. If key is
|
||||
* not NULL, *key * will contain a copy of the key.
|
||||
*
|
||||
* Requires:
|
||||
* 'name' is a valid dns_name_t
|
||||
|
|
@ -74,6 +81,7 @@ dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
|
|||
* 'length' is an integer greater than 0
|
||||
* 'creator' points to a valid dns_name_t or is NULL
|
||||
* 'mctx' is a valid memory context
|
||||
* 'ring' is a valid TSIG keyring
|
||||
* 'key' or '*key' must be NULL
|
||||
*
|
||||
* Returns:
|
||||
|
|
@ -84,12 +92,13 @@ dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
|
|||
*/
|
||||
|
||||
void
|
||||
dns_tsigkey_free(dns_tsigkey_t **key);
|
||||
dns_tsigkey_free(dns_tsigkey_t **key, dns_tsig_keyring_t *ring);
|
||||
/*
|
||||
* Frees the tsig key structure pointed to by 'key'.
|
||||
*
|
||||
* Requires:
|
||||
* 'key' is a valid TSIG key
|
||||
* 'ring' is a valid TSIG keyring containing the key
|
||||
*/
|
||||
|
||||
void
|
||||
|
|
@ -119,7 +128,8 @@ dns_tsig_sign(dns_message_t *msg);
|
|||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg);
|
||||
dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
|
||||
dns_tsig_keyring_t *sring, dns_tsig_keyring_t *dring);
|
||||
/*
|
||||
* Verifies the TSIG record in this message
|
||||
*
|
||||
|
|
@ -129,6 +139,8 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg);
|
|||
* 'msg->tsigkey' is a valid TSIG key if this is a response
|
||||
* 'msg->tsig' is NULL
|
||||
* 'msg->querytsig' is not NULL if this is a response
|
||||
* 'sring' is a valid keyring or NULL
|
||||
* 'dring' is a valid keyring or NULL
|
||||
*
|
||||
* Returns:
|
||||
* DNS_R_SUCCESS
|
||||
|
|
@ -140,28 +152,9 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg);
|
|||
* DNS_R_TSIGVERIFYFAILURE - the TSIG failed to verify
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg);
|
||||
/*
|
||||
* Verifies the TSIG record in this continuation of a TCP response,
|
||||
* if there is one.
|
||||
*
|
||||
* Requires:
|
||||
* 'source' is a valid buffer containing the unparsed message
|
||||
* 'msg' is a valid message
|
||||
* 'msg->tsigkey' is a valid TSIG key
|
||||
* 'msg->tsig' is NULL
|
||||
* 'msg->querytsig' is not NULL
|
||||
*
|
||||
* Returns:
|
||||
* DNS_R_SUCCESS
|
||||
* ISC_R_NOMEMORY
|
||||
* DNS_R_TSIGVERIFYFAILURE - the TSIG failed to verify
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
|
||||
dns_name_t *algorithm);
|
||||
dns_name_t *algorithm, dns_tsig_keyring_t *ring);
|
||||
/*
|
||||
* Returns the TSIG key corresponding to this name and (possibly)
|
||||
* algorithm. Also increments the key's reference counter.
|
||||
|
|
@ -171,6 +164,7 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
|
|||
* '*tsigkey' is NULL
|
||||
* 'name' is a valid dns_name_t
|
||||
* 'algorithm' is a valid dns_name_t or NULL
|
||||
* 'ring' is a valid keyring
|
||||
*
|
||||
* Returns:
|
||||
* ISC_R_SUCCESS
|
||||
|
|
@ -179,15 +173,15 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
|
|||
|
||||
|
||||
isc_result_t
|
||||
dns_tsig_init(isc_log_t *lctx, dns_c_ctx_t *confctx, isc_mem_t *mctx);
|
||||
dns_tsig_init(dns_c_ctx_t *confctx, isc_mem_t *mctx, dns_tsig_keyring_t **ring);
|
||||
/*
|
||||
* Initializes the TSIG subsystem. If confctx is not NULL, any
|
||||
* specified keys are loaded.
|
||||
*
|
||||
* Requires:
|
||||
* 'lctx' is not NULL
|
||||
* 'mctx' is not NULL
|
||||
|
||||
* 'ring' is not NULL, and '*ring' is NULL
|
||||
*
|
||||
* Returns:
|
||||
* ISC_R_SUCCESS
|
||||
* ISC_R_NOMEMORY
|
||||
|
|
@ -195,9 +189,12 @@ dns_tsig_init(isc_log_t *lctx, dns_c_ctx_t *confctx, isc_mem_t *mctx);
|
|||
|
||||
|
||||
void
|
||||
dns_tsig_destroy(void);
|
||||
dns_tsig_destroy(dns_tsig_keyring_t **ring);
|
||||
/*
|
||||
* Frees all data associated with the TSIG subsystem
|
||||
*
|
||||
* Requires:
|
||||
* 'ring' is not NULL
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ typedef struct dns_dispatch dns_dispatch_t;
|
|||
typedef struct dns_dispentry dns_dispentry_t;
|
||||
typedef struct dns_dispatchevent dns_dispatchevent_t;
|
||||
typedef struct dns_tsigkey dns_tsigkey_t;
|
||||
typedef struct dns_tsig_keyring dns_tsig_keyring_t;
|
||||
typedef struct dns_tkey_ctx dns_tkey_ctx_t;
|
||||
typedef struct dns_view dns_view_t;
|
||||
typedef ISC_LIST(dns_view_t) dns_viewlist_t;
|
||||
typedef struct dns_zone dns_zone_t;
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ struct dns_view {
|
|||
isc_task_t * task;
|
||||
isc_event_t resevent;
|
||||
isc_event_t adbevent;
|
||||
dns_tsig_keyring_t * statickeys;
|
||||
dns_tsig_keyring_t * dynamickeys;
|
||||
/* Locked by lock. */
|
||||
unsigned int references;
|
||||
unsigned int attributes;
|
||||
|
|
@ -226,6 +228,26 @@ dns_view_sethints(dns_view_t *view, dns_db_t *hints);
|
|||
* The hints database of 'view' is 'hints'.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring);
|
||||
/*
|
||||
* Set the view's static TSIG keys
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* 'view' is a valid, unfrozen view, whose static TSIG keyring has not
|
||||
* been set.
|
||||
*
|
||||
* 'ring' is a valid TSIG keyring
|
||||
*
|
||||
* Ensures:
|
||||
*
|
||||
* The static TSIG keyring of 'view' is 'ring'.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
isc_result_t
|
||||
dns_view_addzone(dns_view_t *view, dns_zone_t *zone);
|
||||
/*
|
||||
|
|
@ -421,6 +443,21 @@ dns_view_load(dns_view_t *view);
|
|||
* 'view' is a valid.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg);
|
||||
/*
|
||||
* Verifies the signature of a message.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* 'view' is a valid view.
|
||||
* 'source' is a valid buffer containing the message
|
||||
* 'msg' is a valid message
|
||||
*
|
||||
* Returns:
|
||||
* see dns_tsig_verify()
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* DNS_VIEW_H */
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <dns/compress.h>
|
||||
#include <dns/tsig.h>
|
||||
#include <dns/dnssec.h>
|
||||
#include <dns/view.h>
|
||||
|
||||
#define DNS_MESSAGE_OPCODE_MASK 0x7800U
|
||||
#define DNS_MESSAGE_OPCODE_SHIFT 11
|
||||
|
|
@ -287,6 +288,7 @@ msginitprivate(dns_message_t *m)
|
|||
static inline void
|
||||
msginittsig(dns_message_t *m)
|
||||
{
|
||||
m->ring = NULL;
|
||||
m->tsigstatus = m->querytsigstatus = dns_rcode_noerror;
|
||||
m->tsig = m->querytsig = NULL;
|
||||
m->tsigkey = NULL;
|
||||
|
|
@ -455,7 +457,7 @@ msgreset(dns_message_t *msg, isc_boolean_t everything)
|
|||
}
|
||||
|
||||
if (msg->tsigkey != NULL) {
|
||||
dns_tsigkey_free(&msg->tsigkey);
|
||||
dns_tsigkey_free(&msg->tsigkey, msg->ring);
|
||||
msg->tsigkey = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1317,17 +1319,9 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
|
|||
if (r.length != 0)
|
||||
return (DNS_R_FORMERR);
|
||||
|
||||
if (msg->tsigkey != NULL ||
|
||||
!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_TSIG]))
|
||||
if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_TSIG]) ||
|
||||
!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_SIG0]))
|
||||
{
|
||||
if (!msg->tcp_continuation)
|
||||
ret = dns_tsig_verify(source, msg);
|
||||
else
|
||||
ret = dns_tsig_verify_tcp(source, msg);
|
||||
if (ret != DNS_R_SUCCESS)
|
||||
return ret;
|
||||
}
|
||||
else if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_SIG0])) {
|
||||
msg->saved = isc_mem_get(msg->mctx, sizeof(isc_region_t));
|
||||
if (msg->saved == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
|
|
@ -2148,3 +2142,21 @@ dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
|
|||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
|
||||
isc_buffer_t b;
|
||||
|
||||
REQUIRE(DNS_MESSAGE_VALID(msg));
|
||||
REQUIRE(view != NULL);
|
||||
|
||||
if (msg->tsigkey == NULL &&
|
||||
ISC_LIST_EMPTY(msg->sections[DNS_SECTION_TSIG]))
|
||||
return (ISC_R_SUCCESS);
|
||||
if (msg->saved == NULL)
|
||||
return (DNS_R_EXPECTEDTSIG);
|
||||
isc_buffer_init(&b, msg->saved->base, msg->saved->length,
|
||||
ISC_BUFFERTYPE_BINARY);
|
||||
isc_buffer_add(&b, msg->saved->length);
|
||||
return dns_view_checksig(view, &b, msg);
|
||||
}
|
||||
|
|
|
|||
210
lib/dns/tkey.c
210
lib/dns/tkey.c
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* $Id: tkey.c,v 1.15 1999/12/06 12:40:30 brister Exp $
|
||||
* $Id: tkey.c,v 1.16 2000/01/21 20:18:36 bwelling Exp $
|
||||
* Principal Author: Brian Wellington
|
||||
*/
|
||||
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
#include <isc/error.h>
|
||||
#include <isc/list.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/net.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/rwlock.h>
|
||||
|
|
@ -63,12 +64,8 @@
|
|||
} while (0)
|
||||
|
||||
|
||||
static dst_key_t *tkey_dhkey = NULL;
|
||||
static dns_name_t *tkey_domain = NULL;
|
||||
static isc_mem_t *tkey_mctx = NULL;
|
||||
|
||||
isc_result_t
|
||||
dns_tkey_init(isc_log_t *lctx, dns_c_ctx_t *cfg, isc_mem_t *mctx) {
|
||||
dns_tkey_init(dns_c_ctx_t *cfg, isc_mem_t *mctx, dns_tkey_ctx_t **tctx) {
|
||||
isc_result_t result;
|
||||
char *s;
|
||||
int n;
|
||||
|
|
@ -76,11 +73,16 @@ dns_tkey_init(isc_log_t *lctx, dns_c_ctx_t *cfg, isc_mem_t *mctx) {
|
|||
unsigned char data[1024];
|
||||
dns_name_t domain;
|
||||
|
||||
RUNTIME_CHECK(tkey_domain == NULL);
|
||||
RUNTIME_CHECK(tkey_dhkey == NULL);
|
||||
|
||||
REQUIRE(lctx != NULL); /* XXX lctx is now unused. */
|
||||
REQUIRE(mctx != NULL);
|
||||
REQUIRE(tctx != NULL);
|
||||
REQUIRE(*tctx == NULL);
|
||||
|
||||
*tctx = isc_mem_get(mctx, sizeof(dns_tkey_ctx_t));
|
||||
if (*tctx == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
(*tctx)->mctx = mctx;
|
||||
(*tctx)->dhkey = NULL;
|
||||
(*tctx)->domain = NULL;
|
||||
|
||||
if (cfg == NULL)
|
||||
return (ISC_R_SUCCESS);
|
||||
|
|
@ -91,47 +93,50 @@ dns_tkey_init(isc_log_t *lctx, dns_c_ctx_t *cfg, isc_mem_t *mctx) {
|
|||
return (ISC_R_SUCCESS);
|
||||
RETERR(dst_key_fromfile(s, n, DNS_KEYALG_DH,
|
||||
DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
|
||||
mctx, &tkey_dhkey));
|
||||
mctx, &(*tctx)->dhkey));
|
||||
s = NULL;
|
||||
RETERR(dns_c_ctx_gettkeydomain(cfg, &s));
|
||||
dns_name_init(&domain, NULL);
|
||||
tkey_domain = (dns_name_t *) isc_mem_get(mctx, sizeof(dns_name_t));
|
||||
if (tkey_domain == NULL)
|
||||
(*tctx)->domain = (dns_name_t *) isc_mem_get(mctx, sizeof(dns_name_t));
|
||||
if ((*tctx)->domain == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
dns_name_init(tkey_domain, NULL);
|
||||
dns_name_init((*tctx)->domain, NULL);
|
||||
isc_buffer_init(&b, s, strlen(s), ISC_BUFFERTYPE_TEXT);
|
||||
isc_buffer_add(&b, strlen(s));
|
||||
isc_buffer_init(&namebuf, data, sizeof(data), ISC_BUFFERTYPE_BINARY);
|
||||
RETERR(dns_name_fromtext(&domain, &b, dns_rootname, ISC_FALSE,
|
||||
&namebuf));
|
||||
RETERR(dns_name_dup(&domain, mctx, tkey_domain));
|
||||
|
||||
tkey_mctx = mctx;
|
||||
RETERR(dns_name_dup(&domain, mctx, (*tctx)->domain));
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
failure:
|
||||
if (tkey_dhkey != NULL) {
|
||||
dst_key_free(tkey_dhkey);
|
||||
tkey_dhkey = NULL;
|
||||
if ((*tctx)->dhkey != NULL) {
|
||||
dst_key_free((*tctx)->dhkey);
|
||||
(*tctx)->dhkey = NULL;
|
||||
}
|
||||
if (tkey_domain != NULL) {
|
||||
dns_name_free(tkey_domain, mctx);
|
||||
isc_mem_put(mctx, tkey_domain, sizeof(dns_name_t));
|
||||
tkey_domain = NULL;
|
||||
if ((*tctx)->domain != NULL) {
|
||||
dns_name_free((*tctx)->domain, mctx);
|
||||
isc_mem_put(mctx, (*tctx)->domain, sizeof(dns_name_t));
|
||||
(*tctx)->domain = NULL;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
dns_tkey_destroy(void) {
|
||||
if (tkey_mctx == NULL)
|
||||
return;
|
||||
if (tkey_dhkey != NULL)
|
||||
dst_key_free(tkey_dhkey);
|
||||
if (tkey_domain != NULL)
|
||||
isc_mem_put(tkey_mctx, tkey_domain, sizeof(dns_name_t));
|
||||
tkey_mctx = NULL;
|
||||
dns_tkey_destroy(dns_tkey_ctx_t **tctx) {
|
||||
isc_mem_t *mctx;
|
||||
|
||||
REQUIRE(tctx != NULL);
|
||||
REQUIRE(*tctx != NULL);
|
||||
|
||||
if ((*tctx)->dhkey != NULL)
|
||||
dst_key_free((*tctx)->dhkey);
|
||||
if ((*tctx)->domain != NULL)
|
||||
isc_mem_put((*tctx)->mctx, (*tctx)->domain, sizeof(dns_name_t));
|
||||
|
||||
mctx = (*tctx)->mctx;
|
||||
isc_mem_put(mctx, *tctx, sizeof(dns_tkey_ctx_t));
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
|
|
@ -169,6 +174,7 @@ add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata,
|
|||
RETERR(dns_message_gettemprdatalist(msg, &newlist));
|
||||
newlist->rdclass = newrdata->rdclass;
|
||||
newlist->type = newrdata->type;
|
||||
newlist->covers = 0;
|
||||
newlist->ttl = ttl;
|
||||
ISC_LIST_INIT(newlist->rdata);
|
||||
ISC_LIST_APPEND(newlist->rdata, newrdata, link);
|
||||
|
|
@ -191,27 +197,59 @@ add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata,
|
|||
dns_message_puttempname(msg, &newname);
|
||||
if (newlist != NULL)
|
||||
dns_message_puttemprdatalist(msg, &newlist);
|
||||
if (newset != NULL)
|
||||
if (newset != NULL) {
|
||||
dns_rdataset_disassociate(newset);
|
||||
dns_message_puttemprdataset(msg, &newset);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
compute_secret(isc_buffer_t *shared, isc_region_t *randomness,
|
||||
isc_buffer_t *secret)
|
||||
compute_secret(isc_buffer_t *shared, isc_region_t *queryrandomness,
|
||||
isc_region_t *serverrandomness, isc_buffer_t *secret)
|
||||
{
|
||||
dst_context_t ctx;
|
||||
isc_result_t result;
|
||||
isc_region_t r;
|
||||
isc_region_t r, r2;
|
||||
char digests[32];
|
||||
isc_buffer_t b;
|
||||
unsigned int i;
|
||||
|
||||
isc_buffer_init(&b, digests, sizeof(digests), ISC_BUFFERTYPE_BINARY);
|
||||
isc_buffer_used(shared, &r);
|
||||
|
||||
/* MD5 ( query data | DH value ) */
|
||||
RETERR(dst_digest(DST_SIGMODE_INIT, DST_DIGEST_MD5, &ctx, NULL, NULL));
|
||||
RETERR(dst_digest(DST_SIGMODE_UPDATE, DST_DIGEST_MD5, &ctx,
|
||||
queryrandomness, NULL));
|
||||
RETERR(dst_digest(DST_SIGMODE_UPDATE, DST_DIGEST_MD5, &ctx, &r, NULL));
|
||||
if (randomness->length != 0)
|
||||
RETERR(dst_digest(DST_SIGMODE_UPDATE, DST_DIGEST_MD5,
|
||||
&ctx, randomness, secret));
|
||||
RETERR(dst_digest(DST_SIGMODE_FINAL, DST_DIGEST_MD5, &ctx, NULL,
|
||||
secret));
|
||||
RETERR(dst_digest(DST_SIGMODE_FINAL, DST_DIGEST_MD5, &ctx, NULL, &b));
|
||||
|
||||
/* MD5 ( server data | DH value ) */
|
||||
RETERR(dst_digest(DST_SIGMODE_INIT, DST_DIGEST_MD5, &ctx, NULL, NULL));
|
||||
RETERR(dst_digest(DST_SIGMODE_UPDATE, DST_DIGEST_MD5, &ctx,
|
||||
serverrandomness, NULL));
|
||||
RETERR(dst_digest(DST_SIGMODE_UPDATE, DST_DIGEST_MD5, &ctx, &r, NULL));
|
||||
RETERR(dst_digest(DST_SIGMODE_FINAL, DST_DIGEST_MD5, &ctx, NULL, &b));
|
||||
|
||||
/* XOR ( DH value, MD5-1 | MD5-2) */
|
||||
isc_buffer_available(secret, &r);
|
||||
isc_buffer_used(shared, &r2);
|
||||
if (r.length < sizeof(digests) || r.length < r2.length)
|
||||
return (ISC_R_NOSPACE);
|
||||
if (r2.length > sizeof(digests)) {
|
||||
memcpy(r.base, r2.base, r2.length);
|
||||
for (i = 0; i < sizeof(digests); i++)
|
||||
r.base[i] ^= digests[i];
|
||||
isc_buffer_add(secret, r2.length);
|
||||
}
|
||||
else {
|
||||
memcpy(r.base, digests, sizeof(digests));
|
||||
for (i = 0; i < r2.length; i++)
|
||||
r.base[i] ^= r2.base[i];
|
||||
isc_buffer_add(secret, sizeof(digests));
|
||||
}
|
||||
|
||||
failure:
|
||||
return result;
|
||||
|
||||
|
|
@ -219,8 +257,9 @@ compute_secret(isc_buffer_t *shared, isc_region_t *randomness,
|
|||
|
||||
static isc_result_t
|
||||
process_dhtkey(dns_message_t *msg, dns_name_t *name,
|
||||
dns_rdata_generic_tkey_t *tkeyin,
|
||||
dns_rdata_generic_tkey_t *tkeyout, dns_namelist_t *namelist)
|
||||
dns_rdata_generic_tkey_t *tkeyin, dns_tkey_ctx_t *tctx,
|
||||
dns_rdata_generic_tkey_t *tkeyout,
|
||||
dns_tsig_keyring_t *ring, dns_namelist_t *namelist)
|
||||
{
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
dns_name_t *keyname, ourname, signer, *creator;
|
||||
|
|
@ -229,14 +268,14 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name,
|
|||
isc_boolean_t found_key = ISC_FALSE, found_incompatible = ISC_FALSE;
|
||||
dst_key_t *pubkey = NULL;
|
||||
isc_buffer_t ourkeybuf, ournamein, ournameout, *shared = NULL;
|
||||
isc_region_t r, ourkeyr;
|
||||
isc_region_t r, r2, ourkeyr;
|
||||
isc_uint32_t ourttl;
|
||||
unsigned char keydata[DST_KEY_MAXSIZE];
|
||||
unsigned char namedata[1024];
|
||||
dns_tsigkey_t *tsigkey;
|
||||
unsigned int sharedsize;
|
||||
isc_buffer_t randombuf, secret;
|
||||
unsigned char *randomdata = NULL, secretdata[TKEY_RANDOM_AMOUNT];
|
||||
unsigned char *randomdata = NULL, secretdata[256];
|
||||
|
||||
/* Look for a DH KEY record that will work with ours */
|
||||
result = dns_message_firstname(msg, DNS_SECTION_ADDITIONAL);
|
||||
|
|
@ -261,7 +300,7 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name,
|
|||
}
|
||||
if (dst_key_alg(pubkey) == DNS_KEYALG_DH) {
|
||||
if (dst_key_paramcompare(pubkey,
|
||||
tkey_dhkey))
|
||||
tctx->dhkey))
|
||||
{
|
||||
found_key = ISC_TRUE;
|
||||
goto got_key;
|
||||
|
|
@ -290,13 +329,13 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name,
|
|||
|
||||
isc_buffer_init(&ourkeybuf, keydata, sizeof(keydata),
|
||||
ISC_BUFFERTYPE_BINARY);
|
||||
RETERR(dst_key_todns(tkey_dhkey, &ourkeybuf));
|
||||
RETERR(dst_key_todns(tctx->dhkey, &ourkeybuf));
|
||||
isc_buffer_used(&ourkeybuf, &ourkeyr);
|
||||
dns_rdata_fromregion(&ourkeyrdata, dns_rdataclass_in,
|
||||
dns_rdatatype_key, &ourkeyr);
|
||||
isc_buffer_init(&ournamein, dst_key_name(tkey_dhkey),
|
||||
strlen(dst_key_name(tkey_dhkey)), ISC_BUFFERTYPE_TEXT);
|
||||
isc_buffer_add(&ournamein, strlen(dst_key_name(tkey_dhkey)));
|
||||
isc_buffer_init(&ournamein, dst_key_name(tctx->dhkey),
|
||||
strlen(dst_key_name(tctx->dhkey)), ISC_BUFFERTYPE_TEXT);
|
||||
isc_buffer_add(&ournamein, strlen(dst_key_name(tctx->dhkey)));
|
||||
isc_buffer_init(&ournameout, namedata, sizeof(namedata),
|
||||
ISC_BUFFERTYPE_BINARY);
|
||||
dns_name_init(&ourname, NULL);
|
||||
|
|
@ -326,11 +365,11 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name,
|
|||
RETERR(add_rdata_to_list(msg, &ourname, &ourkeyrdata, ourttl,
|
||||
namelist));
|
||||
|
||||
RETERR(dst_secret_size(tkey_dhkey, &sharedsize));
|
||||
RETERR(dst_secret_size(tctx->dhkey, &sharedsize));
|
||||
RETERR(isc_buffer_allocate(msg->mctx, &shared, sharedsize,
|
||||
ISC_BUFFERTYPE_BINARY));
|
||||
|
||||
RETERR(dst_computesecret(pubkey, tkey_dhkey, shared));
|
||||
RETERR(dst_computesecret(pubkey, tctx->dhkey, shared));
|
||||
|
||||
isc_buffer_init(&secret, secretdata, sizeof(secretdata),
|
||||
ISC_BUFFERTYPE_BINARY);
|
||||
|
|
@ -345,7 +384,9 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name,
|
|||
RETERR(dst_random_get(TKEY_RANDOM_AMOUNT, &randombuf));
|
||||
|
||||
isc_buffer_used(&randombuf, &r);
|
||||
RETERR(compute_secret(shared, &r, &secret));
|
||||
r2.base = tkeyin->key;
|
||||
r2.length = tkeyin->keylen;
|
||||
RETERR(compute_secret(shared, &r2, &r, &secret));
|
||||
|
||||
dns_name_init(&signer, NULL);
|
||||
result = dns_message_signer(msg, &signer);
|
||||
|
|
@ -359,7 +400,8 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name,
|
|||
isc_buffer_used(&secret, &r);
|
||||
tsigkey = NULL;
|
||||
result = dns_tsigkey_create(name, &tkeyin->algorithm, r.base, r.length,
|
||||
ISC_TRUE, creator, msg->mctx, &tsigkey);
|
||||
ISC_TRUE, creator, msg->mctx, ring,
|
||||
&tsigkey);
|
||||
isc_buffer_free(&shared);
|
||||
shared = NULL;
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
|
|
@ -387,6 +429,7 @@ process_dhtkey(dns_message_t *msg, dns_name_t *name,
|
|||
|
||||
ISC_LIST_UNLINK(*namelist, tname, link);
|
||||
tset = ISC_LIST_HEAD(tname->list);
|
||||
dns_rdataset_disassociate(tset);
|
||||
dns_message_puttemprdataset(msg, &tset);
|
||||
dns_message_puttempname(msg, &tname);
|
||||
tname = next;
|
||||
|
|
@ -401,6 +444,7 @@ static isc_result_t
|
|||
process_deletetkey(dns_message_t *msg, dns_name_t *name,
|
||||
dns_rdata_generic_tkey_t *tkeyin,
|
||||
dns_rdata_generic_tkey_t *tkeyout,
|
||||
dns_tsig_keyring_t *ring,
|
||||
dns_namelist_t *namelist)
|
||||
{
|
||||
isc_result_t result;
|
||||
|
|
@ -412,7 +456,7 @@ process_deletetkey(dns_message_t *msg, dns_name_t *name,
|
|||
tkeyout = tkeyout;
|
||||
namelist = namelist;
|
||||
|
||||
result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm);
|
||||
result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
tkeyout->error = dns_tsigerror_badname;
|
||||
|
||||
|
|
@ -448,13 +492,15 @@ process_deletetkey(dns_message_t *msg, dns_name_t *name,
|
|||
*/
|
||||
dns_tsigkey_setdeleted(tsigkey);
|
||||
/* Release the reference */
|
||||
dns_tsigkey_free(&tsigkey);
|
||||
dns_tsigkey_free(&tsigkey, ring);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_tkey_processquery(dns_message_t *msg) {
|
||||
dns_tkey_processquery(dns_message_t *msg, dns_tkey_ctx_t *tctx,
|
||||
dns_tsig_keyring_t *ring)
|
||||
{
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
dns_rdata_generic_tkey_t tkeyin, tkeyout;
|
||||
dns_name_t *qname, *name, *keyname;
|
||||
|
|
@ -463,6 +509,10 @@ dns_tkey_processquery(dns_message_t *msg) {
|
|||
isc_buffer_t *dynbuf = NULL;
|
||||
dns_namelist_t namelist;
|
||||
|
||||
REQUIRE(msg != NULL);
|
||||
REQUIRE(tctx != NULL);
|
||||
REQUIRE(ring != NULL);
|
||||
|
||||
/* Need to do this to determine if this should be freed later */
|
||||
memset(&tkeyin, 0, sizeof(dns_rdata_generic_tkey_t));
|
||||
|
||||
|
|
@ -570,16 +620,16 @@ dns_tkey_processquery(dns_message_t *msg) {
|
|||
goto failure;
|
||||
}
|
||||
}
|
||||
result = dns_name_concatenate(&prefix, tkey_domain,
|
||||
result = dns_name_concatenate(&prefix, tctx->domain,
|
||||
keyname, buf);
|
||||
dns_message_takebuffer(msg, &buf);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto failure;
|
||||
|
||||
result = dns_tsigkey_find(&tsigkey, keyname, NULL);
|
||||
result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
tkeyout.error = dns_tsigerror_badname;
|
||||
dns_tsigkey_free(&tsigkey);
|
||||
dns_tsigkey_free(&tsigkey, ring);
|
||||
goto failure_with_tkey;
|
||||
}
|
||||
else if (result != ISC_R_NOTFOUND)
|
||||
|
|
@ -595,13 +645,13 @@ dns_tkey_processquery(dns_message_t *msg) {
|
|||
|
||||
switch (tkeyin.mode) {
|
||||
case DNS_TKEYMODE_DIFFIEHELLMAN:
|
||||
RETERR(process_dhtkey(msg, keyname, &tkeyin,
|
||||
&tkeyout, &namelist));
|
||||
RETERR(process_dhtkey(msg, keyname, &tkeyin, tctx,
|
||||
&tkeyout, ring, &namelist));
|
||||
tkeyout.error = dns_rcode_noerror;
|
||||
break;
|
||||
case DNS_TKEYMODE_DELETE:
|
||||
RETERR(process_deletetkey(msg, keyname, &tkeyin,
|
||||
&tkeyout, &namelist));
|
||||
&tkeyout, ring, &namelist));
|
||||
tkeyout.error = dns_rcode_noerror;
|
||||
break;
|
||||
case DNS_TKEYMODE_SERVERASSIGNED:
|
||||
|
|
@ -712,8 +762,10 @@ buildquery(dns_message_t *msg, dns_name_t *name,
|
|||
dns_message_puttempname(msg, &qname);
|
||||
if (aname != NULL)
|
||||
dns_message_puttempname(msg, &aname);
|
||||
if (question != NULL)
|
||||
if (question != NULL) {
|
||||
dns_rdataset_disassociate(question);
|
||||
dns_message_puttemprdataset(msg, &question);
|
||||
}
|
||||
if (dynbuf != NULL)
|
||||
isc_buffer_free(&dynbuf);
|
||||
return (result);
|
||||
|
|
@ -738,8 +790,6 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name,
|
|||
REQUIRE(name != NULL);
|
||||
REQUIRE(algorithm != NULL);
|
||||
|
||||
nonce = nonce; /* until the new spec is done */
|
||||
|
||||
tkey.common.rdclass = dns_rdataclass_in /**/;
|
||||
tkey.common.rdtype = dns_rdatatype_tkey;
|
||||
ISC_LINK_INIT(&tkey.common, link);
|
||||
|
|
@ -748,9 +798,12 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name,
|
|||
dns_name_clone(algorithm, &tkey.algorithm);
|
||||
tkey.inception = tkey.expire = 0;
|
||||
tkey.mode = DNS_TKEYMODE_DIFFIEHELLMAN;
|
||||
isc_buffer_region(nonce, &r);
|
||||
tkey.error = 0;
|
||||
tkey.keylen = tkey.otherlen = 0;
|
||||
tkey.key = tkey.other = NULL;
|
||||
tkey.key = r.base;
|
||||
tkey.keylen = r.length;
|
||||
tkey.other = NULL;
|
||||
tkey.otherlen = 0;
|
||||
|
||||
RETERR(buildquery(msg, name, &tkey));
|
||||
|
||||
|
|
@ -836,7 +889,8 @@ find_tkey(dns_message_t *msg, dns_name_t **name, dns_rdata_t *rdata) {
|
|||
|
||||
isc_result_t
|
||||
dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
|
||||
dst_key_t *key, dns_tsigkey_t **outkey)
|
||||
dst_key_t *key, isc_buffer_t *nonce,
|
||||
dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring)
|
||||
{
|
||||
dns_rdata_t qtkeyrdata, rtkeyrdata;
|
||||
dns_name_t keyname, *tkeyname, *theirkeyname, *ourkeyname, *tempname;
|
||||
|
|
@ -845,10 +899,10 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
|
|||
dst_key_t *theirkey;
|
||||
dns_tsigkey_t *tsigkey;
|
||||
dns_rdata_generic_tkey_t qtkey, rtkey;
|
||||
unsigned char keydata[1024], secretdata[16];
|
||||
unsigned char keydata[1024], secretdata[256];
|
||||
unsigned int sharedsize;
|
||||
isc_buffer_t keysrc, keybuf, *shared = NULL, secret;
|
||||
isc_region_t r;
|
||||
isc_region_t r, r2;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(qmsg != NULL);
|
||||
|
|
@ -858,6 +912,7 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
|
|||
REQUIRE(dst_key_isprivate(key));
|
||||
if (outkey != NULL)
|
||||
REQUIRE(*outkey == NULL);
|
||||
REQUIRE(ring != NULL);
|
||||
|
||||
RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata));
|
||||
RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, rmsg->mctx));
|
||||
|
|
@ -930,13 +985,14 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
|
|||
|
||||
r.base = rtkey.key;
|
||||
r.length = rtkey.keylen;
|
||||
RETERR(compute_secret(shared, &r, &secret));
|
||||
isc_buffer_region(nonce, &r2);
|
||||
RETERR(compute_secret(shared, &r2, &r, &secret));
|
||||
|
||||
isc_buffer_used(&secret, &r);
|
||||
tsigkey = NULL;
|
||||
result = dns_tsigkey_create(tkeyname, &rtkey.algorithm,
|
||||
r.base, r.length, ISC_TRUE,
|
||||
NULL, rmsg->mctx, outkey);
|
||||
NULL, rmsg->mctx, ring, outkey);
|
||||
isc_buffer_free(&shared);
|
||||
return (result);
|
||||
|
||||
|
|
@ -948,7 +1004,9 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
|
|||
}
|
||||
|
||||
isc_result_t
|
||||
dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg) {
|
||||
dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
|
||||
dns_tsig_keyring_t *ring)
|
||||
{
|
||||
dns_rdata_t qtkeyrdata, rtkeyrdata;
|
||||
dns_name_t *tkeyname, *tempname;
|
||||
dns_rdata_generic_tkey_t qtkey, rtkey;
|
||||
|
|
@ -975,12 +1033,12 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg) {
|
|||
goto failure;
|
||||
}
|
||||
|
||||
RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm));
|
||||
RETERR(dns_tsigkey_find(&tsigkey, tkeyname, &rtkey.algorithm,ring));
|
||||
|
||||
/* Mark the key as deleted */
|
||||
dns_tsigkey_setdeleted(tsigkey);
|
||||
/* Release the reference */
|
||||
dns_tsigkey_free(&tsigkey);
|
||||
dns_tsigkey_free(&tsigkey, ring);
|
||||
|
||||
failure:
|
||||
return (result);
|
||||
|
|
|
|||
153
lib/dns/tsig.c
153
lib/dns/tsig.c
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* $Id: tsig.c,v 1.36 1999/12/17 21:09:34 bwelling Exp $
|
||||
* $Id: tsig.c,v 1.37 2000/01/21 20:18:37 bwelling Exp $
|
||||
* Principal Author: Brian Wellington
|
||||
*/
|
||||
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
#include <isc/error.h>
|
||||
#include <isc/list.h>
|
||||
#include <isc/net.h>
|
||||
#include <isc/once.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/rwlock.h>
|
||||
#include <isc/stdtime.h>
|
||||
|
|
@ -54,19 +55,20 @@
|
|||
#define TSIG_MAGIC 0x54534947 /* TSIG */
|
||||
#define VALID_TSIG_KEY(x) ((x) != NULL && (x)->magic == TSIG_MAGIC)
|
||||
|
||||
/* XXXBEW If an unsorted list isn't good enough, this can be updated */
|
||||
static ISC_LIST(dns_tsigkey_t) tsigkeys;
|
||||
static isc_rwlock_t tsiglock;
|
||||
static isc_mem_t *tsig_mctx = NULL;
|
||||
#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
|
||||
|
||||
static isc_once_t once = ISC_ONCE_INIT;
|
||||
static dns_name_t hmacmd5_name;
|
||||
dns_name_t *dns_tsig_hmacmd5_name = NULL;
|
||||
|
||||
#define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
|
||||
static isc_result_t
|
||||
dns_tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg);
|
||||
|
||||
isc_result_t
|
||||
dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
|
||||
unsigned char *secret, int length, isc_boolean_t generated,
|
||||
dns_name_t *creator, isc_mem_t *mctx, dns_tsigkey_t **key)
|
||||
dns_name_t *creator, isc_mem_t *mctx,
|
||||
dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
|
||||
{
|
||||
isc_buffer_t b, nameb;
|
||||
char namestr[1025];
|
||||
|
|
@ -144,19 +146,19 @@ dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
|
|||
goto cleanup_algorithm;
|
||||
|
||||
ISC_LINK_INIT(tkey, link);
|
||||
isc_rwlock_lock(&tsiglock, isc_rwlocktype_write);
|
||||
tmp = ISC_LIST_HEAD(tsigkeys);
|
||||
isc_rwlock_lock(&ring->lock, isc_rwlocktype_write);
|
||||
tmp = ISC_LIST_HEAD(ring->keys);
|
||||
while (tmp != NULL) {
|
||||
if (dns_name_equal(&tkey->name, &tmp->name)) {
|
||||
ret = ISC_R_EXISTS;
|
||||
isc_rwlock_unlock(&tsiglock,
|
||||
isc_rwlock_unlock(&ring->lock,
|
||||
isc_rwlocktype_write);
|
||||
goto cleanup_algorithm;
|
||||
}
|
||||
tmp = ISC_LIST_NEXT(tmp, link);
|
||||
}
|
||||
ISC_LIST_APPEND(tsigkeys, tkey, link);
|
||||
isc_rwlock_unlock(&tsiglock, isc_rwlocktype_write);
|
||||
ISC_LIST_APPEND(ring->keys, tkey, link);
|
||||
isc_rwlock_unlock(&ring->lock, isc_rwlocktype_write);
|
||||
}
|
||||
else
|
||||
tkey->key = NULL;
|
||||
|
|
@ -189,7 +191,7 @@ cleanup_key:
|
|||
}
|
||||
|
||||
static void
|
||||
tsigkey_free(dns_tsigkey_t **key) {
|
||||
tsigkey_free(dns_tsigkey_t **key, dns_tsig_keyring_t *ring) {
|
||||
dns_tsigkey_t *tkey;
|
||||
|
||||
REQUIRE(key != NULL);
|
||||
|
|
@ -199,9 +201,9 @@ tsigkey_free(dns_tsigkey_t **key) {
|
|||
|
||||
tkey->magic = 0;
|
||||
if (tkey->key != NULL) {
|
||||
isc_rwlock_lock(&tsiglock, isc_rwlocktype_write);
|
||||
ISC_LIST_UNLINK(tsigkeys, tkey, link);
|
||||
isc_rwlock_unlock(&tsiglock, isc_rwlocktype_write);
|
||||
isc_rwlock_lock(&ring->lock, isc_rwlocktype_write);
|
||||
ISC_LIST_UNLINK(ring->keys, tkey, link);
|
||||
isc_rwlock_unlock(&ring->lock, isc_rwlocktype_write);
|
||||
}
|
||||
dns_name_free(&tkey->name, tkey->mctx);
|
||||
dns_name_free(&tkey->algorithm, tkey->mctx);
|
||||
|
|
@ -215,7 +217,7 @@ tsigkey_free(dns_tsigkey_t **key) {
|
|||
}
|
||||
|
||||
void
|
||||
dns_tsigkey_free(dns_tsigkey_t **key) {
|
||||
dns_tsigkey_free(dns_tsigkey_t **key, dns_tsig_keyring_t *ring) {
|
||||
dns_tsigkey_t *tkey;
|
||||
|
||||
REQUIRE(key != NULL);
|
||||
|
|
@ -230,7 +232,7 @@ dns_tsigkey_free(dns_tsigkey_t **key) {
|
|||
return;
|
||||
}
|
||||
isc_mutex_unlock(&tkey->lock);
|
||||
tsigkey_free(key);
|
||||
tsigkey_free(key, ring);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -526,7 +528,9 @@ cleanup_struct:
|
|||
}
|
||||
|
||||
isc_result_t
|
||||
dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg) {
|
||||
dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
|
||||
dns_tsig_keyring_t *sring, dns_tsig_keyring_t *dring)
|
||||
{
|
||||
dns_rdata_any_tsig_t *tsig;
|
||||
isc_region_t r, source_r, header_r, sig_r;
|
||||
isc_buffer_t databuf;
|
||||
|
|
@ -549,6 +553,9 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg) {
|
|||
if (msg->tsigkey != NULL)
|
||||
REQUIRE(VALID_TSIG_KEY(msg->tsigkey));
|
||||
|
||||
if (msg->tcp_continuation)
|
||||
return(dns_tsig_verify_tcp(source, msg));
|
||||
|
||||
/* There should be a TSIG record... */
|
||||
if (ISC_LIST_EMPTY(msg->sections[DNS_SECTION_TSIG]))
|
||||
return (DNS_R_EXPECTEDTSIG);
|
||||
|
|
@ -598,13 +605,23 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg) {
|
|||
|
||||
/* Find dns_tsigkey_t based on keyname */
|
||||
if (msg->tsigkey == NULL) {
|
||||
ret = dns_tsigkey_find(&tsigkey, keyname, &tsig->algorithm);
|
||||
ret = ISC_R_NOTFOUND;
|
||||
if (sring != NULL)
|
||||
ret = dns_tsigkey_find(&tsigkey, keyname,
|
||||
&tsig->algorithm, sring);
|
||||
if (ret == ISC_R_NOTFOUND && dring != NULL)
|
||||
ret = dns_tsigkey_find(&tsigkey, keyname,
|
||||
&tsig->algorithm, dring);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
if (dring == NULL) {
|
||||
ret = DNS_R_TSIGVERIFYFAILURE;
|
||||
goto cleanup_struct;
|
||||
}
|
||||
msg->tsigstatus = dns_tsigerror_badkey;
|
||||
msg->tsigkey = NULL;
|
||||
ret = dns_tsigkey_create(keyname, &tsig->algorithm,
|
||||
NULL, 0, ISC_FALSE, NULL,
|
||||
mctx, &msg->tsigkey);
|
||||
mctx, dring, &msg->tsigkey);
|
||||
if (ret != ISC_R_SUCCESS)
|
||||
goto cleanup_struct;
|
||||
return (DNS_R_TSIGVERIFYFAILURE);
|
||||
|
|
@ -751,7 +768,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg) {
|
|||
|
||||
cleanup_key:
|
||||
if (dns_tsigkey_empty(msg->tsigkey)) {
|
||||
dns_tsigkey_free(&msg->tsigkey);
|
||||
dns_tsigkey_free(&msg->tsigkey, dring);
|
||||
msg->tsigkey = NULL;
|
||||
}
|
||||
cleanup_struct:
|
||||
|
|
@ -762,7 +779,7 @@ cleanup_emptystruct:
|
|||
return (ret);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
static isc_result_t
|
||||
dns_tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
|
||||
dns_rdata_any_tsig_t *tsig = NULL;
|
||||
isc_region_t r, source_r, header_r, sig_r;
|
||||
|
|
@ -928,16 +945,17 @@ cleanup_emptystruct:
|
|||
|
||||
isc_result_t
|
||||
dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
|
||||
dns_name_t *algorithm)
|
||||
dns_name_t *algorithm, dns_tsig_keyring_t *ring)
|
||||
{
|
||||
dns_tsigkey_t *key;
|
||||
|
||||
REQUIRE(tsigkey != NULL);
|
||||
REQUIRE(*tsigkey == NULL);
|
||||
REQUIRE(name != NULL);
|
||||
REQUIRE(ring != NULL);
|
||||
|
||||
isc_rwlock_lock(&tsiglock, isc_rwlocktype_read);
|
||||
key = ISC_LIST_HEAD(tsigkeys);
|
||||
isc_rwlock_lock(&ring->lock, isc_rwlocktype_read);
|
||||
key = ISC_LIST_HEAD(ring->keys);
|
||||
while (key != NULL) {
|
||||
if (dns_name_equal(&key->name, name) &&
|
||||
(algorithm == NULL ||
|
||||
|
|
@ -948,21 +966,24 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
|
|||
key->refs++;
|
||||
isc_mutex_unlock(&key->lock);
|
||||
*tsigkey = key;
|
||||
isc_rwlock_unlock(&tsiglock, isc_rwlocktype_read);
|
||||
isc_rwlock_unlock(&ring->lock, isc_rwlocktype_read);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
key = ISC_LIST_NEXT(key, link);
|
||||
}
|
||||
isc_rwlock_unlock(&tsiglock, isc_rwlocktype_read);
|
||||
isc_rwlock_unlock(&ring->lock, isc_rwlocktype_read);
|
||||
*tsigkey = NULL;
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
add_initial_keys(dns_c_kdeflist_t *list, isc_mem_t *mctx) {
|
||||
add_initial_keys(dns_c_kdeflist_t *list, dns_tsig_keyring_t *ring,
|
||||
isc_mem_t *mctx)
|
||||
{
|
||||
isc_lex_t *lex = NULL;
|
||||
dns_c_kdef_t *key;
|
||||
unsigned char *secret = NULL;
|
||||
int secretalloc = 0;
|
||||
int secretlen = 0;
|
||||
isc_result_t ret;
|
||||
|
||||
|
|
@ -1008,7 +1029,7 @@ add_initial_keys(dns_c_kdeflist_t *list, isc_mem_t *mctx) {
|
|||
ret = ISC_R_BADBASE64;
|
||||
goto failure;
|
||||
}
|
||||
secretlen = strlen(key->secret) * 3 / 4;
|
||||
secretalloc = secretlen = strlen(key->secret) * 3 / 4;
|
||||
secret = isc_mem_get(mctx, secretlen);
|
||||
if (secret == NULL) {
|
||||
ret = ISC_R_NOMEMORY;
|
||||
|
|
@ -1028,12 +1049,13 @@ add_initial_keys(dns_c_kdeflist_t *list, isc_mem_t *mctx) {
|
|||
ret = isc_base64_tobuffer(lex, &secretbuf, -1);
|
||||
if (ret != ISC_R_SUCCESS)
|
||||
goto failure;
|
||||
secretlen = ISC_BUFFER_USEDCOUNT(&secretbuf);
|
||||
isc_lex_close(lex);
|
||||
isc_lex_destroy(&lex);
|
||||
|
||||
ret = dns_tsigkey_create(&keyname, &alg, secret, secretlen,
|
||||
ISC_FALSE, NULL, mctx, NULL);
|
||||
isc_mem_put(mctx, secret, secretlen);
|
||||
ISC_FALSE, NULL, mctx, ring, NULL);
|
||||
isc_mem_put(mctx, secret, secretalloc);
|
||||
secret = NULL;
|
||||
if (ret != ISC_R_SUCCESS)
|
||||
goto failure;
|
||||
|
|
@ -1050,18 +1072,33 @@ add_initial_keys(dns_c_kdeflist_t *list, isc_mem_t *mctx) {
|
|||
|
||||
}
|
||||
|
||||
static void
|
||||
dns_tsig_inithmac() {
|
||||
isc_region_t r;
|
||||
char *str = "\010HMAC-MD5\007SIG-ALG\003REG\003INT";
|
||||
dns_name_init(&hmacmd5_name, NULL);
|
||||
r.base = str;
|
||||
r.length = strlen(str) + 1;
|
||||
dns_name_fromregion(&hmacmd5_name, &r);
|
||||
dns_tsig_hmacmd5_name = &hmacmd5_name;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_tsig_init(isc_log_t *lctx, dns_c_ctx_t *confctx, isc_mem_t *mctx) {
|
||||
isc_buffer_t hmacsrc, namebuf;
|
||||
dns_tsig_init(dns_c_ctx_t *confctx, isc_mem_t *mctx, dns_tsig_keyring_t **ring)
|
||||
{
|
||||
isc_result_t ret;
|
||||
dns_name_t hmac_name;
|
||||
unsigned char data[32];
|
||||
dns_c_kdeflist_t *keylist = NULL;
|
||||
|
||||
REQUIRE(lctx != NULL); /* XXX lctx is now unused. */
|
||||
REQUIRE(mctx != NULL);
|
||||
REQUIRE(ring != NULL);
|
||||
REQUIRE(*ring == NULL);
|
||||
|
||||
ret = isc_rwlock_init(&tsiglock, 0, 0);
|
||||
RUNTIME_CHECK(isc_once_do(&once, dns_tsig_inithmac) == ISC_R_SUCCESS);
|
||||
*ring = isc_mem_get(mctx, sizeof(dns_tsig_keyring_t));
|
||||
if (ring == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
|
||||
ret = isc_rwlock_init(&(*ring)->lock, 0, 0);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"isc_rwlock_init() failed: %s",
|
||||
|
|
@ -1069,34 +1106,17 @@ dns_tsig_init(isc_log_t *lctx, dns_c_ctx_t *confctx, isc_mem_t *mctx) {
|
|||
return (DNS_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
ISC_LIST_INIT(tsigkeys);
|
||||
isc_buffer_init(&hmacsrc, DNS_TSIG_HMACMD5,
|
||||
strlen(DNS_TSIG_HMACMD5), ISC_BUFFERTYPE_TEXT);
|
||||
isc_buffer_add(&hmacsrc, strlen(DNS_TSIG_HMACMD5));
|
||||
isc_buffer_init(&namebuf, data, sizeof(data), ISC_BUFFERTYPE_BINARY);
|
||||
|
||||
dns_name_init(&hmac_name, NULL);
|
||||
ret = dns_name_fromtext(&hmac_name, &hmacsrc, NULL, ISC_TRUE, &namebuf);
|
||||
if (ret != ISC_R_SUCCESS)
|
||||
return (ret);
|
||||
|
||||
dns_tsig_hmacmd5_name = isc_mem_get(mctx, sizeof(dns_name_t));
|
||||
if (dns_tsig_hmacmd5_name == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
dns_name_init(dns_tsig_hmacmd5_name, NULL);
|
||||
ret = dns_name_dup(&hmac_name, mctx, dns_tsig_hmacmd5_name);
|
||||
if (ret != ISC_R_SUCCESS)
|
||||
goto failure;
|
||||
ISC_LIST_INIT((*ring)->keys);
|
||||
|
||||
if (confctx != NULL) {
|
||||
ret = dns_c_ctx_getkdeflist(confctx, &keylist);
|
||||
if (ret == ISC_R_SUCCESS)
|
||||
ret = add_initial_keys(keylist, mctx);
|
||||
ret = add_initial_keys(keylist, *ring, mctx);
|
||||
else if (ret != ISC_R_NOTFOUND)
|
||||
goto failure;
|
||||
}
|
||||
|
||||
tsig_mctx = mctx;
|
||||
(*ring)->mctx = mctx;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
|
|
@ -1106,15 +1126,16 @@ dns_tsig_init(isc_log_t *lctx, dns_c_ctx_t *confctx, isc_mem_t *mctx) {
|
|||
}
|
||||
|
||||
void
|
||||
dns_tsig_destroy() {
|
||||
if (tsig_mctx == NULL)
|
||||
return;
|
||||
while (!ISC_LIST_EMPTY(tsigkeys)) {
|
||||
dns_tsigkey_t *key = ISC_LIST_HEAD(tsigkeys);
|
||||
dns_tsig_destroy(dns_tsig_keyring_t **ring) {
|
||||
REQUIRE(ring != NULL);
|
||||
REQUIRE(*ring != NULL);
|
||||
|
||||
while (!ISC_LIST_EMPTY((*ring)->keys)) {
|
||||
dns_tsigkey_t *key = ISC_LIST_HEAD((*ring)->keys);
|
||||
key->refs = 0;
|
||||
key->deleted = ISC_TRUE;
|
||||
tsigkey_free(&key);
|
||||
tsigkey_free(&key, *ring);
|
||||
}
|
||||
dns_name_free(dns_tsig_hmacmd5_name, tsig_mctx);
|
||||
isc_mem_put(tsig_mctx, dns_tsig_hmacmd5_name, sizeof(dns_name_t));
|
||||
|
||||
*ring = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,9 +33,11 @@
|
|||
#include <dns/db.h>
|
||||
#include <dns/events.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/message.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/rdataset.h>
|
||||
#include <dns/resolver.h>
|
||||
#include <dns/tsig.h>
|
||||
#include <dns/view.h>
|
||||
#include <dns/zone.h>
|
||||
#include <dns/zt.h>
|
||||
|
|
@ -106,6 +108,9 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
|||
view->task = NULL;
|
||||
view->references = 1;
|
||||
view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN);
|
||||
view->statickeys = NULL;
|
||||
view->dynamickeys = NULL;
|
||||
result = dns_tsig_init(NULL, view->mctx, &view->dynamickeys);
|
||||
ISC_LINK_INIT(view, link);
|
||||
ISC_EVENT_INIT(&view->resevent, sizeof view->resevent, 0, NULL,
|
||||
DNS_EVENT_VIEWRESSHUTDOWN, resolver_shutdown,
|
||||
|
|
@ -348,6 +353,20 @@ dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
|
|||
dns_db_attach(hints, &view->hints);
|
||||
}
|
||||
|
||||
void
|
||||
dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring) {
|
||||
|
||||
/*
|
||||
* Set the view's static TSIG keyring
|
||||
*/
|
||||
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
REQUIRE(view->statickeys == NULL);
|
||||
REQUIRE(ring != NULL);
|
||||
|
||||
view->statickeys = ring;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
|
||||
isc_result_t result;
|
||||
|
|
@ -783,3 +802,14 @@ dns_view_load(dns_view_t *view) {
|
|||
|
||||
dns_zt_load(view->zonetable);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg) {
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
REQUIRE(source != NULL);
|
||||
REQUIRE(DNS_MESSAGE_VALID(msg));
|
||||
|
||||
return dns_tsig_verify(source, msg, view->statickeys,
|
||||
view->dynamickeys);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue