s4/dns_server: include request MAC in TSIG response MAC calculation
authorRalph Boehme <slow@samba.org>
Mon, 23 May 2016 17:09:05 +0000 (19:09 +0200)
committerGarming Sam <garming@samba.org>
Wed, 15 Jun 2016 22:06:27 +0000 (00:06 +0200)
According to RFC 2845 "4.2 TSIG on Answers", when the request is signed,
the request MAC must be included in the response MAC calculation.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11520

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
source4/dns_server/dns_crypto.c

index 502887fec888c323f2a0edd6c4ee6dc71b5cab25..a8d76a4bb2691e729cd223a4d099849577fdd2dc 100644 (file)
@@ -243,12 +243,14 @@ WERROR dns_sign_tsig(struct dns_server *dns,
        time_t current_time = time(NULL);
        DATA_BLOB packet_blob, tsig_blob, sig;
        uint8_t *buffer = NULL;
+       uint8_t *p = NULL;
        size_t buffer_len = 0;
        struct dns_server_tkey * tkey = NULL;
        struct dns_res_rec *tsig = talloc_zero(mem_ctx, struct dns_res_rec);
 
        struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx,
                        struct dns_fake_tsig_rec);
+       size_t mac_size = 0;
 
        if (tsig == NULL) {
                return WERR_NOMEM;
@@ -298,15 +300,44 @@ WERROR dns_sign_tsig(struct dns_server *dns,
                return DNS_ERR(SERVER_FAILURE);
        }
 
-       buffer_len = packet_blob.length + tsig_blob.length;
+       if (state->tsig != NULL) {
+               mac_size = state->tsig->rdata.tsig_record.mac_size;
+       }
+
+       buffer_len = mac_size;
+
+       buffer_len += packet_blob.length;
+       if (buffer_len < packet_blob.length) {
+               return WERR_INVALID_PARAM;
+       }
+       buffer_len += tsig_blob.length;
+       if (buffer_len < tsig_blob.length) {
+               return WERR_INVALID_PARAM;
+       }
+
        buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_len);
        if (buffer == NULL) {
                return WERR_NOMEM;
        }
 
-       memcpy(buffer, packet_blob.data, packet_blob.length);
-       memcpy(buffer+packet_blob.length, tsig_blob.data, tsig_blob.length);
+       p = buffer;
+
+       /*
+        * RFC 2845 "4.2 TSIG on Answers", how to lay out the buffer
+        * that we're going to sign:
+        * 1. MAC of request (if present)
+        * 2. Outgoing packet
+        * 3. TSIG record
+        */
+       if (mac_size > 0) {
+               memcpy(p, state->tsig->rdata.tsig_record.mac, mac_size);
+               p += mac_size;
+       }
+
+       memcpy(p, packet_blob.data, packet_blob.length);
+       p += packet_blob.length;
 
+       memcpy(p, tsig_blob.data, tsig_blob.length);
 
        status = gensec_sign_packet(tkey->gensec, mem_ctx, buffer, buffer_len,
                                    buffer, buffer_len, &sig);