mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 14:07:59 +00:00
TCP additions
This commit is contained in:
@@ -115,6 +115,25 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg);
|
|||||||
* DNS_R_TSIGVERIFYFAILURE - the TSIG failed to verify
|
* 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
|
isc_result_t
|
||||||
dns_tsig_findkey(dns_tsig_key_t **tsigkey, dns_name_t *name,
|
dns_tsig_findkey(dns_tsig_key_t **tsigkey, dns_name_t *name,
|
||||||
dns_name_t *algorithm);
|
dns_name_t *algorithm);
|
||||||
|
238
lib/dns/tsig.c
238
lib/dns/tsig.c
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Id: tsig.c,v 1.9 1999/09/10 02:42:12 explorer Exp $
|
* $Id: tsig.c,v 1.10 1999/09/10 14:56:36 bwelling Exp $
|
||||||
* Principal Author: Brian Wellington
|
* Principal Author: Brian Wellington
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -266,6 +266,7 @@ dns_tsig_sign(dns_message_t *msg) {
|
|||||||
unsigned char header[DNS_MESSAGE_HEADERLEN];
|
unsigned char header[DNS_MESSAGE_HEADERLEN];
|
||||||
isc_buffer_t headerbuf;
|
isc_buffer_t headerbuf;
|
||||||
|
|
||||||
|
/* Digest the header */
|
||||||
isc_buffer_init(&headerbuf, header, sizeof header,
|
isc_buffer_init(&headerbuf, header, sizeof header,
|
||||||
ISC_BUFFERTYPE_BINARY);
|
ISC_BUFFERTYPE_BINARY);
|
||||||
dns_message_renderheader(msg, &headerbuf);
|
dns_message_renderheader(msg, &headerbuf);
|
||||||
@@ -273,31 +274,39 @@ dns_tsig_sign(dns_message_t *msg) {
|
|||||||
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r, NULL);
|
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r, NULL);
|
||||||
if (ret != ISC_R_SUCCESS)
|
if (ret != ISC_R_SUCCESS)
|
||||||
goto cleanup_other;
|
goto cleanup_other;
|
||||||
|
|
||||||
|
/* Digest the remainder of the message */
|
||||||
isc_buffer_used(msg->buffer, &r);
|
isc_buffer_used(msg->buffer, &r);
|
||||||
isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
|
isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
|
||||||
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r, NULL);
|
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r, NULL);
|
||||||
if (ret != ISC_R_SUCCESS)
|
if (ret != ISC_R_SUCCESS)
|
||||||
goto cleanup_other;
|
goto cleanup_other;
|
||||||
|
|
||||||
/* Digest the name, class, ttl, alg */
|
if (msg->tcp_continuation == 0) {
|
||||||
dns_name_toregion(&key->name, &r);
|
/* Digest the name, class, ttl, alg */
|
||||||
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r, NULL);
|
dns_name_toregion(&key->name, &r);
|
||||||
if (ret != ISC_R_SUCCESS)
|
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r,
|
||||||
goto cleanup_other;
|
NULL);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_other;
|
||||||
|
|
||||||
isc_buffer_clear(&databuf);
|
isc_buffer_clear(&databuf);
|
||||||
isc_buffer_putuint16(&databuf, dns_rdataclass_any);
|
isc_buffer_putuint16(&databuf, dns_rdataclass_any);
|
||||||
isc_buffer_putuint32(&databuf, 0); /* ttl */
|
isc_buffer_putuint32(&databuf, 0); /* ttl */
|
||||||
isc_buffer_used(&databuf, &r);
|
isc_buffer_used(&databuf, &r);
|
||||||
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r, NULL);
|
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r,
|
||||||
if (ret != ISC_R_SUCCESS)
|
NULL);
|
||||||
goto cleanup_other;
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_other;
|
||||||
dns_name_toregion(tsig->algorithm, &r);
|
|
||||||
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r, NULL);
|
|
||||||
if (ret != ISC_R_SUCCESS)
|
|
||||||
goto cleanup_other;
|
|
||||||
|
|
||||||
|
dns_name_toregion(tsig->algorithm, &r);
|
||||||
|
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r,
|
||||||
|
NULL);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_other;
|
||||||
|
|
||||||
|
}
|
||||||
|
/* Digest the timesigned and fudge */
|
||||||
isc_buffer_clear(&databuf);
|
isc_buffer_clear(&databuf);
|
||||||
if (tsig->error != dns_tsigerror_badtime) {
|
if (tsig->error != dns_tsigerror_badtime) {
|
||||||
isc_buffer_putuint16(&databuf,
|
isc_buffer_putuint16(&databuf,
|
||||||
@@ -313,21 +322,32 @@ dns_tsig_sign(dns_message_t *msg) {
|
|||||||
querysigned & 0xFFFFFFFF);
|
querysigned & 0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
isc_buffer_putuint16(&databuf, tsig->fudge);
|
isc_buffer_putuint16(&databuf, tsig->fudge);
|
||||||
isc_buffer_putuint16(&databuf, tsig->error);
|
|
||||||
isc_buffer_putuint16(&databuf, tsig->otherlen);
|
|
||||||
|
|
||||||
isc_buffer_used(&databuf, &r);
|
isc_buffer_used(&databuf, &r);
|
||||||
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r, NULL);
|
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r, NULL);
|
||||||
if (ret != ISC_R_SUCCESS)
|
if (ret != ISC_R_SUCCESS)
|
||||||
goto cleanup_other;
|
goto cleanup_other;
|
||||||
|
|
||||||
if (tsig->otherlen > 0) {
|
if (msg->tcp_continuation == 0) {
|
||||||
r.length = tsig->otherlen;
|
/* Digest the error and other data length */
|
||||||
r.base = tsig->other;
|
isc_buffer_clear(&databuf);
|
||||||
|
isc_buffer_putuint16(&databuf, tsig->error);
|
||||||
|
isc_buffer_putuint16(&databuf, tsig->otherlen);
|
||||||
|
|
||||||
|
isc_buffer_used(&databuf, &r);
|
||||||
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r,
|
ret = dst_sign(DST_SIGMODE_UPDATE, key->key, &ctx, &r,
|
||||||
NULL);
|
NULL);
|
||||||
if (ret != ISC_R_SUCCESS)
|
if (ret != ISC_R_SUCCESS)
|
||||||
goto cleanup_other;
|
goto cleanup_other;
|
||||||
|
|
||||||
|
/* Digest the error and other data */
|
||||||
|
if (tsig->otherlen > 0) {
|
||||||
|
r.length = tsig->otherlen;
|
||||||
|
r.base = tsig->other;
|
||||||
|
ret = dst_sign(DST_SIGMODE_UPDATE, key->key,
|
||||||
|
&ctx, &r, NULL);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_other;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tsig->siglen = dst_sig_size(key->key);
|
tsig->siglen = dst_sig_size(key->key);
|
||||||
@@ -462,10 +482,6 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg) {
|
|||||||
if (ret != ISC_R_SUCCESS)
|
if (ret != ISC_R_SUCCESS)
|
||||||
goto cleanup_emptystruct;
|
goto cleanup_emptystruct;
|
||||||
|
|
||||||
isc_buffer_used(source, &r);
|
|
||||||
memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
|
|
||||||
isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
|
|
||||||
|
|
||||||
/* Do the key name and algorithm match that of the query? */
|
/* Do the key name and algorithm match that of the query? */
|
||||||
if (is_response(msg) &&
|
if (is_response(msg) &&
|
||||||
(!dns_name_equal(keyname, &msg->tsigkey->name) ||
|
(!dns_name_equal(keyname, &msg->tsigkey->name) ||
|
||||||
@@ -530,6 +546,11 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Extract the header */
|
||||||
|
isc_buffer_used(source, &r);
|
||||||
|
memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
|
||||||
|
isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
|
||||||
|
|
||||||
/* Decrement the additional field counter */
|
/* Decrement the additional field counter */
|
||||||
memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
|
memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
|
||||||
addcount = htons(ntohs(addcount) - 1);
|
addcount = htons(ntohs(addcount) - 1);
|
||||||
@@ -635,6 +656,167 @@ cleanup_emptystruct:
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
isc_buffer_t databuf;
|
||||||
|
unsigned char data[32];
|
||||||
|
dns_name_t *keyname;
|
||||||
|
dns_rdataset_t *dataset;
|
||||||
|
dns_rdata_t rdata;
|
||||||
|
isc_stdtime_t now;
|
||||||
|
isc_result_t ret;
|
||||||
|
dst_key_t *key = NULL;
|
||||||
|
unsigned char header[DNS_MESSAGE_HEADERLEN];
|
||||||
|
isc_mem_t *mctx;
|
||||||
|
isc_uint16_t addcount;
|
||||||
|
isc_boolean_t has_tsig = ISC_FALSE;
|
||||||
|
|
||||||
|
REQUIRE(source != NULL);
|
||||||
|
REQUIRE(msg != NULL);
|
||||||
|
REQUIRE(msg->tsig == NULL);
|
||||||
|
REQUIRE(msg->tsigkey != NULL);
|
||||||
|
REQUIRE(msg->tcp_continuation == 1);
|
||||||
|
REQUIRE(is_response(msg));
|
||||||
|
REQUIRE(msg->querytsig != NULL);
|
||||||
|
|
||||||
|
mctx = msg->mctx;
|
||||||
|
|
||||||
|
ret = dns_message_firstname(msg, DNS_SECTION_TSIG);
|
||||||
|
if (ret == ISC_R_SUCCESS) {
|
||||||
|
has_tsig = ISC_TRUE;
|
||||||
|
|
||||||
|
keyname = NULL;
|
||||||
|
dns_message_currentname(msg, DNS_SECTION_TSIG, &keyname);
|
||||||
|
dataset = ISC_LIST_HEAD(keyname->list);
|
||||||
|
ret = dns_rdataset_first(dataset);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
return (ret);
|
||||||
|
dns_rdataset_current(dataset, &rdata);
|
||||||
|
tsig = (dns_rdata_any_tsig_t *)
|
||||||
|
isc_mem_get(mctx, sizeof(dns_rdata_any_tsig_t));
|
||||||
|
if (tsig == NULL)
|
||||||
|
return (ISC_R_NOMEMORY);
|
||||||
|
msg->tsig = tsig;
|
||||||
|
ret = dns_rdata_tostruct(&rdata, tsig, mctx);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_emptystruct;
|
||||||
|
|
||||||
|
/* Do the key name and algorithm match that of the query? */
|
||||||
|
if (!dns_name_equal(keyname, &msg->tsigkey->name) ||
|
||||||
|
!dns_name_equal(tsig->algorithm, msg->querytsig->algorithm))
|
||||||
|
{
|
||||||
|
msg->tsigstatus = dns_tsigerror_badkey;
|
||||||
|
return (DNS_R_TSIGVERIFYFAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is the time ok? */
|
||||||
|
ret = isc_stdtime_get(&now);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_struct;
|
||||||
|
if (abs(now - tsig->timesigned) > tsig->fudge) {
|
||||||
|
msg->tsigstatus = dns_tsigerror_badtime;
|
||||||
|
return (DNS_R_TSIGVERIFYFAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key = msg->tsigkey->key;
|
||||||
|
|
||||||
|
if (msg->tsigctx == NULL) {
|
||||||
|
ret = dst_verify(DST_SIGMODE_INIT, key, &msg->tsigctx,
|
||||||
|
NULL, NULL);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_struct;
|
||||||
|
|
||||||
|
isc_buffer_init(&databuf, data, sizeof(data),
|
||||||
|
ISC_BUFFERTYPE_BINARY);
|
||||||
|
isc_buffer_putuint16(&databuf, msg->querytsig->siglen);
|
||||||
|
isc_buffer_used(&databuf, &r);
|
||||||
|
ret = dst_verify(DST_SIGMODE_UPDATE, key, &msg->tsigctx,
|
||||||
|
&r, NULL);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_struct;
|
||||||
|
if (msg->querytsig->siglen > 0) {
|
||||||
|
r.length = msg->querytsig->siglen;
|
||||||
|
r.base = msg->querytsig->signature;
|
||||||
|
ret = dst_verify(DST_SIGMODE_UPDATE, key,
|
||||||
|
&msg->tsigctx, &r, NULL);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_struct;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract the header */
|
||||||
|
isc_buffer_used(source, &r);
|
||||||
|
memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
|
||||||
|
isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
|
||||||
|
|
||||||
|
/* Decrement the additional field counter if necessary */
|
||||||
|
if (has_tsig) {
|
||||||
|
memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
|
||||||
|
addcount = htons(ntohs(addcount) - 1);
|
||||||
|
memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX Put in the original id */
|
||||||
|
|
||||||
|
/* Digest the modified header */
|
||||||
|
header_r.base = (unsigned char *) header;
|
||||||
|
header_r.length = DNS_MESSAGE_HEADERLEN;
|
||||||
|
ret = dst_verify(DST_SIGMODE_UPDATE, key, &msg->tsigctx, &header_r,
|
||||||
|
NULL);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_struct;
|
||||||
|
|
||||||
|
/* Digest all non-TSIG records. */
|
||||||
|
isc_buffer_used(source, &source_r);
|
||||||
|
r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
|
||||||
|
if (has_tsig)
|
||||||
|
r.length = msg->tsigstart - DNS_MESSAGE_HEADERLEN;
|
||||||
|
else
|
||||||
|
r.length = source_r.length - DNS_MESSAGE_HEADERLEN;
|
||||||
|
ret = dst_verify(DST_SIGMODE_UPDATE, key, &msg->tsigctx, &r, NULL);
|
||||||
|
if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_struct;
|
||||||
|
|
||||||
|
/* Digest the time signed and fudge */
|
||||||
|
if (has_tsig) {
|
||||||
|
isc_buffer_init(&databuf, data, sizeof(data),
|
||||||
|
ISC_BUFFERTYPE_BINARY);
|
||||||
|
isc_buffer_putuint16(&databuf, tsig->timesigned >> 32);
|
||||||
|
isc_buffer_putuint32(&databuf, tsig->timesigned & 0xFFFFFFFF);
|
||||||
|
isc_buffer_putuint16(&databuf, tsig->fudge);
|
||||||
|
isc_buffer_used(&databuf, &r);
|
||||||
|
ret = dst_verify(DST_SIGMODE_UPDATE, key, &msg->tsigctx, &r,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
sig_r.base = tsig->signature;
|
||||||
|
sig_r.length = tsig->siglen;
|
||||||
|
|
||||||
|
ret = dst_verify(DST_SIGMODE_FINAL, key, &msg->tsigctx, NULL,
|
||||||
|
&sig_r);
|
||||||
|
if (ret == DST_R_VERIFYFINALFAILURE) {
|
||||||
|
msg->tsigstatus = dns_tsigerror_badsig;
|
||||||
|
return (DNS_R_TSIGVERIFYFAILURE);
|
||||||
|
}
|
||||||
|
else if (ret != ISC_R_SUCCESS)
|
||||||
|
goto cleanup_struct;
|
||||||
|
|
||||||
|
msg->tsigctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->tsigstatus = dns_rcode_noerror;
|
||||||
|
return (ISC_R_SUCCESS);
|
||||||
|
|
||||||
|
cleanup_struct:
|
||||||
|
dns_rdata_freestruct(tsig);
|
||||||
|
cleanup_emptystruct:
|
||||||
|
msg->tsig = NULL;
|
||||||
|
isc_mem_put(mctx, tsig, sizeof(dns_rdata_any_tsig_t));
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
dns_tsig_findkey(dns_tsig_key_t **tsigkey, dns_name_t *name,
|
dns_tsig_findkey(dns_tsig_key_t **tsigkey, dns_name_t *name,
|
||||||
dns_name_t *algorithm)
|
dns_name_t *algorithm)
|
||||||
|
Reference in New Issue
Block a user