]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
allow TSIG key to be added to message structure after parsing
authorEvan Hunt <each@isc.org>
Tue, 29 Jan 2019 19:39:06 +0000 (11:39 -0800)
committerEvan Hunt <each@isc.org>
Wed, 30 Jan 2019 19:46:11 +0000 (11:46 -0800)
up until now, message->tsigkey could only be set during parsing
of the request, but gss-tsig allows one to be created afterward.

this commit adds a new flag to the message structure, `new_tsigkey`,
which indicates that in this case it's okay for `dns_message_settsigkey()`
to be run on a message after parsing, without hitting any assertions due
to the lack of a TSIG in the request. this allows us to keep the current
restriction in place generally, but add an exception for TKEY processing.
it's probably better to just remove the restriction entirely (see next
commit).

lib/dns/include/dns/message.h
lib/dns/message.c
lib/dns/tkey.c
lib/dns/tsig.c

index 6f389aa2df2f77bc12a33267b1ea56eaa841a290..314639238815ca6c362a1520cc41b26afe32e64b 100644 (file)
@@ -178,9 +178,9 @@ typedef int dns_messagetextflag_t;
 #define DNS_MESSAGERENDER_PARTIAL      0x0002  /*%< allow a partial rdataset */
 #define DNS_MESSAGERENDER_OMITDNSSEC   0x0004  /*%< omit DNSSEC records */
 #define DNS_MESSAGERENDER_PREFER_A     0x0008  /*%< prefer A records in
-                                                     additional section. */
+                                                    additional section. */
 #define DNS_MESSAGERENDER_PREFER_AAAA  0x0010  /*%< prefer AAAA records in
-                                                 additional section. */
+                                                    additional section. */
 /* Obsolete: DNS_MESSAGERENDER_FILTER_AAAA     0x0020  */
 
 typedef struct dns_msgblock dns_msgblock_t;
@@ -224,6 +224,7 @@ struct dns_message {
        unsigned int                    cc_bad : 1;
        unsigned int                    tkey : 1;
        unsigned int                    rdclass_set : 1;
+       unsigned int                    new_tsigkey : 1;
 
        unsigned int                    opt_reserved;
        unsigned int                    sig_reserved;
index f5847006281e21fdb7ddd39954b996f0fbc3ea29..d9c8cba17f1a3abfc7d1b30815c799d3f312159e 100644 (file)
@@ -432,6 +432,7 @@ msginit(dns_message_t *m) {
        m->tkey = 0;
        m->rdclass_set = 0;
        m->querytsig = NULL;
+       m->new_tsigkey = 0;
 }
 
 static inline void
@@ -2801,7 +2802,7 @@ dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
         */
 
        REQUIRE(DNS_MESSAGE_VALID(msg));
-       REQUIRE(msg->state == DNS_SECTION_ANY);
+       REQUIRE(msg->state == DNS_SECTION_ANY || msg->new_tsigkey == 1);
 
        if (key == NULL && msg->tsigkey != NULL) {
                if (msg->sig_reserved != 0) {
index 4bade507ccef0e2a89c9122c2a71384ef4138b16..9b206ce19844c7e9de1d07d6bfe75b40a2c27d2b 100644 (file)
@@ -625,28 +625,20 @@ process_gsstkey(dns_message_t *msg, dns_name_t *name, dns_rdata_tkey_t *tkeyin,
        tkey_log("process_gsstkey(): dns_tsigerror_noerror");   /* XXXSRA */
 
        /*
-        * [#821] WMM: So we found a TKEY to respond with.  We don't know if
-        * the request is TSIG signed, but if it is not we need to make an
-        * effort so that the response is signed, as described in the except
-        * case in RFC 2845 Section 2.2:
-        *
-        *   The server MUST not generate a signed response to an unsigned
-        *   request, except in case of response to client's unsigned TKEY
-        *   query if secret key is established on server side after server
-        *   processed client's query.  Signing responses to unsigned TKEY
-        *   queries MUST be explicitly specified in the description of an
-        *   individual secret key establishment algorithm.
-        *
-        * In dns_message_reply() it is checked whether to TSIG sign the
-        * response by checking if msg->tsigkey is non-NULL.  A first naive
-        * attempt to set the tsigkey here with:
-        *
-         *      RETERR(dns_message_settsigkey(msg, tsigkey));
-        *
-        * is not the right approach, but captures the idea of what needs
-        * to be done: signal that the msg needs to be TSIG signed.
+        * We found a TKEY to respond with.  We don't know if
+        * the request is TSIG signed, but if it is not we need to make
+        * sure the response is signed (RFC 2845 secton 2.2).
         */
 
+       if (tsigkey != NULL) {
+               /*
+                * First, we have to set the message to accept a new
+                * TSIG key; normally they can only be set during parsing.
+                */
+               msg->new_tsigkey = 1;
+               dns_message_settsigkey(msg, tsigkey);
+       }
+
        return (ISC_R_SUCCESS);
 
 failure:
index 2afccef53e31eb21b5398409b0061837477b6f36..26c561cef025175dbb0fcf114f212a773d34fb07 100644 (file)
@@ -782,8 +782,9 @@ dns_tsig_sign(dns_message_t *msg) {
         * If this is a response, there should be a query tsig.
         */
        response = is_response(msg);
-       if (response && msg->querytsig == NULL)
+       if (response && (msg->querytsig == NULL && msg->new_tsigkey == 0)) {
                return (DNS_R_EXPECTEDTSIG);
+       }
 
        dynbuf = NULL;
 
@@ -804,7 +805,7 @@ dns_tsig_sign(dns_message_t *msg) {
 
        isc_buffer_init(&databuf, data, sizeof(data));
 
-       if (response)
+       if (response && msg->new_tsigkey == 0)
                tsig.error = msg->querytsigstatus;
        else
                tsig.error = dns_rcode_noerror;
@@ -843,7 +844,7 @@ dns_tsig_sign(dns_message_t *msg) {
                /*
                 * If this is a response, digest the request's MAC.
                 */
-               if (response) {
+               if (response && msg->new_tsigkey == 0) {
                        dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
 
                        INSIST(msg->verified_sig);