TMP s4 dns: Get the server to do the full TSIG routine
authorKai Blin <kai@samba.org>
Thu, 29 Mar 2012 13:06:39 +0000 (15:06 +0200)
committerKai Blin <kai@samba.org>
Fri, 13 Apr 2012 16:56:24 +0000 (18:56 +0200)
Doesn't pass dig's verification step yet, wonder what the matter is there

source4/dns_server/dns_crypto.c
utils/dns-tsig.c

index 08d6cc12b5a9b7b5c506e51e86b788c59649d1ad..465d0890b9f8e669f29b37461df205b80c59f155 100644 (file)
@@ -91,6 +91,9 @@ static WERROR dns_generate_tsig_mac(TALLOC_CTX *mem_ctx,
        enum ndr_err_code ndr_err;
        uint16_t dummy16;
        uint32_t dummy32;
+       /*FIXME: Don't fake these, use ndr to convert the strings */
+       const char *fake_name = "\x4test";
+       const char *fake_alg = "\x8hmac-md5\7sig-alg\3reg\3int";
 
        if (key == NULL) {
                DEBUG(1, ("No key found, bailing out\n"));
@@ -111,7 +114,7 @@ static WERROR dns_generate_tsig_mac(TALLOC_CTX *mem_ctx,
        /* Build up the MAC as per RFC2845 */
        hmac_md5_init_rfc2104(key->data, key->length, ctx);
 
-       /* 4.2 request MAC, if this is a reply */
+       /* 4.2 on replies, also hash the request MAC */
        if (req_mac != NULL) {
                hmac_md5_update(req_mac, req_mac_length, ctx);
        }
@@ -120,7 +123,7 @@ static WERROR dns_generate_tsig_mac(TALLOC_CTX *mem_ctx,
        hmac_md5_update(blob.data, blob.length, ctx);
 
        /* 3.4.2 tsig variables */
-       hmac_md5_update((const uint8_t *)tsig->name, strlen(tsig->name), ctx);
+       hmac_md5_update((const uint8_t *)fake_name, strlen(fake_name)+1, ctx);
 
        dummy16 = htons(tsig->rr_class);
        hmac_md5_update((const uint8_t *)&dummy16, 2, ctx);
@@ -128,8 +131,8 @@ static WERROR dns_generate_tsig_mac(TALLOC_CTX *mem_ctx,
        dummy32 = htonl(tsig->ttl);
        hmac_md5_update((const uint8_t *)&dummy32, 4, ctx);
 
-       hmac_md5_update((const uint8_t *)tsig->rdata.tsig_record.algorithm_name,
-                       strlen(tsig->rdata.tsig_record.algorithm_name), ctx);
+       hmac_md5_update((const uint8_t *)fake_alg,
+                       strlen(fake_alg)+1, ctx);
 
        dummy16 = htons(tsig->rdata.tsig_record.time_prefix);
        hmac_md5_update((const uint8_t *)&dummy16, 2, ctx);
@@ -159,7 +162,6 @@ static WERROR dns_generate_tsig_mac(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
-
 WERROR dns_verify_tsig(struct dns_server *dns,
                       struct dns_request_state *state,
                       struct dns_name_packet *packet)
@@ -188,6 +190,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
                return DNS_ERR(FORMAT_ERROR);
        }
 
+       NDR_PRINT_DEBUG(dns_name_packet, packet);
        /* We got a TSIG, so we need to sign our reply */
        state->sign = true;
 
@@ -210,9 +213,18 @@ WERROR dns_verify_tsig(struct dns_server *dns,
                                       NULL, 0, &mac, &mac_length);
        W_ERROR_NOT_OK_RETURN(werror);
 
-       dump_data(1, mac, mac_length);
-       state->tsig_error = DNS_RCODE_BADKEY;
-       return DNS_ERR(NOTAUTH);
+
+       if (memcmp(state->tsig->rdata.tsig_record.mac, mac, mac_length) != 0) {
+               DEBUG(1, ("TSIG MAC mismatch\n"));
+               dump_data(1, state->tsig->rdata.tsig_record.mac,
+                         state->tsig->rdata.tsig_record.mac_size);
+               dump_data(1, mac, mac_length);
+               state->tsig_error = DNS_RCODE_BADSIG;
+               return DNS_ERR(NOTAUTH);
+       }
+
+       /* FIXME: Do a time check here, too. */
+       return WERR_OK;
 }
 
 /*FIXME: calculate a real tsig here */
@@ -223,12 +235,21 @@ WERROR dns_sign_tsig(struct dns_server *dns,
 {
        WERROR werror;
        time_t current_time = time(NULL);
+       uint16_t mac_size;
+       uint8_t *mac;
+       struct dns_server_key *key;
        struct dns_res_rec *tsig = talloc_zero(packet, struct dns_res_rec);
        W_ERROR_HAVE_NO_MEMORY(tsig);
 
        tsig->name = talloc_strdup(tsig, state->tsig->name);
        W_ERROR_HAVE_NO_MEMORY(tsig->name);
 
+       key = dns_find_tsig_key(dns, tsig->name);
+       if (key == NULL) {
+               state->flags |= DNS_RCODE_NOTAUTH;
+               state->tsig_error = DNS_RCODE_BADKEY;
+       }
+
        tsig->rr_class = DNS_QCLASS_ANY;
        tsig->rr_type = DNS_QTYPE_TSIG;
        tsig->ttl = 0;
@@ -243,10 +264,14 @@ WERROR dns_sign_tsig(struct dns_server *dns,
        tsig->rdata.tsig_record.other_size = 0;
        tsig->rdata.tsig_record.other_data = NULL;
 
-       /* And here's the part where we fake stuff */
-       tsig->rdata.tsig_record.mac_size = 0;
-       tsig->rdata.tsig_record.mac = NULL;
+       werror = dns_generate_tsig_mac(packet, key, packet, tsig,
+                                      state->tsig->rdata.tsig_record.mac,
+                                      state->tsig->rdata.tsig_record.mac_size,
+                                      &mac, &mac_size);
+       W_ERROR_NOT_OK_RETURN(werror);
 
+       tsig->rdata.tsig_record.mac_size = mac_size;
+       tsig->rdata.tsig_record.mac = mac;
 
        if (packet->arcount == 0) {
                packet->additional = talloc_zero(packet, struct dns_res_rec);
index efa8a6c7ef6a9dee1bd3d446084efb36b9570a92..68c3d2fb26c6dc2578d31fee9058bba615440744 100644 (file)
@@ -75,6 +75,23 @@ static struct dns_name_packet *make_name_packet(TALLOC_CTX *mem_ctx)
        return packet;
 }
 
+static char *dns_get_string_wire_format(TALLOC_CTX *mem_ctx, const char* string)
+{
+       DATA_BLOB blob;
+       char *wire_format;
+       enum ndr_err_code ndr_err;
+
+       ndr_err = ndr_push_struct_blob(&blob, mem_ctx, string,
+                       (ndr_push_flags_fn_t)ndr_push_dns_string);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return NULL;
+       }
+
+       wire_format = talloc_strdup(mem_ctx, blob.data);
+       dump_data(1, wire_format, strlen(wire_format) + 1);
+       return wire_format;
+}
+
 static WERROR dns_generate_tsig_mac(TALLOC_CTX *mem_ctx,
                                    const struct dns_server_key *key,
                                    const struct dns_name_packet *packet,
@@ -89,6 +106,8 @@ static WERROR dns_generate_tsig_mac(TALLOC_CTX *mem_ctx,
        enum ndr_err_code ndr_err;
        uint16_t dummy16;
        uint32_t dummy32;
+       char *fake_name;
+       char *fake_alg;
 
        if (key == NULL) {
                DEBUG(1, ("No key found, bailing out\n"));
@@ -109,14 +128,12 @@ static WERROR dns_generate_tsig_mac(TALLOC_CTX *mem_ctx,
        /* Build up the MAC as per RFC2845 */
        hmac_md5_init_rfc2104(key->data, key->length, ctx);
 
-       dump_data(1, blob.data, blob.length);
-
        /* 3.4.1 dns message */
        hmac_md5_update(blob.data, blob.length, ctx);
 
        /* 3.4.2 tsig variables */
-       dump_data(1, tsig->name, strlen(tsig->name)+1);
-       hmac_md5_update((const uint8_t *)tsig->name, strlen(tsig->name)+1, ctx);
+       fake_name = dns_get_string_wire_format(mem_ctx, tsig->name);
+       hmac_md5_update((const uint8_t *)fake_name, strlen(fake_name)+1, ctx);
 
        dummy16 = htons(tsig->rr_class);
        hmac_md5_update((const uint8_t *)&dummy16, 2, ctx);
@@ -124,10 +141,10 @@ static WERROR dns_generate_tsig_mac(TALLOC_CTX *mem_ctx,
        dummy32 = htonl(tsig->ttl);
        hmac_md5_update((const uint8_t *)&dummy32, 4, ctx);
 
-       dump_data(1, tsig->rdata.tsig_record.algorithm_name,
-                 strlen(tsig->rdata.tsig_record.algorithm_name)+1);
-       hmac_md5_update((const uint8_t *)tsig->rdata.tsig_record.algorithm_name,
-                       strlen(tsig->rdata.tsig_record.algorithm_name)+1, ctx);
+       fake_alg = dns_get_string_wire_format(mem_ctx,
+                       tsig->rdata.tsig_record.algorithm_name);
+       hmac_md5_update((const uint8_t *)fake_alg,
+                       strlen(fake_alg)+1, ctx);
 
        dummy16 = htons(tsig->rdata.tsig_record.time_prefix);
        hmac_md5_update((const uint8_t *)&dummy16, 2, ctx);
@@ -168,7 +185,7 @@ static WERROR sign_tsig(TALLOC_CTX *mem_ctx,
        struct dns_res_rec *tsig = talloc_zero(packet, struct dns_res_rec);
        W_ERROR_HAVE_NO_MEMORY(tsig);
 
-       tsig->name = talloc_strdup(tsig, "\x4test");
+       tsig->name = talloc_strdup(tsig, "test");
        W_ERROR_HAVE_NO_MEMORY(tsig->name);
 
        tsig->rr_class = DNS_QCLASS_ANY;
@@ -176,7 +193,7 @@ static WERROR sign_tsig(TALLOC_CTX *mem_ctx,
        tsig->ttl = 0;
        tsig->length = UINT16_MAX;
        tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig,
-                       "\x8hmac-md5\x7sig-alg\x3reg\x3int");
+                       "hmac-md5.sig-alg.reg.int");
        tsig->rdata.tsig_record.time_prefix = 0;
        tsig->rdata.tsig_record.time = 0x4f74260d;
        tsig->rdata.tsig_record.fudge = 300;
@@ -187,30 +204,8 @@ static WERROR sign_tsig(TALLOC_CTX *mem_ctx,
 
        werror = dns_generate_tsig_mac(mem_ctx, key, packet, tsig,
                                       &mac, &mac_length);
-
-       /* And here's the part where we fake stuff */
-       fake_mac = talloc_zero_size(tsig, 16);
-       fake_mac[0]  = 0xc9;
-       fake_mac[1]  = 0x49;
-       fake_mac[2]  = 0xcd;
-       fake_mac[3]  = 0x39;
-       fake_mac[4]  = 0xf5;
-       fake_mac[5]  = 0xf5;
-       fake_mac[6]  = 0x9d;
-       fake_mac[7]  = 0xfa;
-       fake_mac[8]  = 0x73;
-       fake_mac[9]  = 0xc6;
-       fake_mac[10] = 0xfe;
-       fake_mac[11] = 0x42;
-       fake_mac[12] = 0x12;
-       fake_mac[13] = 0x8c;
-       fake_mac[14] = 0xf1;
-       fake_mac[15] = 0xfa;
-       tsig->rdata.tsig_record.mac_size = 16;
-       tsig->rdata.tsig_record.mac = fake_mac;
-
-       dump_data(1, mac, mac_length);
-       dump_data(1, fake_mac, 16);
+       tsig->rdata.tsig_record.mac = mac;
+       tsig->rdata.tsig_record.mac_size = mac_length;
 
        if (packet->arcount == 0) {
                packet->additional = talloc_zero(packet, struct dns_res_rec);
@@ -243,12 +238,10 @@ int main(int argc, char **argv)
        DATA_BLOB out, in;
        int ret = 0;
 
-#if 0
        if (argc < 2) {
                usage();
                exit(1);
        }
-#endif
 
        ev = tevent_context_init(mem_ctx);
        setup_logging("samba-dig", DEBUG_STDERR);
@@ -259,13 +252,11 @@ int main(int argc, char **argv)
        key = talloc_zero(mem_ctx, struct dns_server_key);
        key->name = talloc_strdup(key, "test");
 
-       /* FIXME: 12??? */
        key->length = 12;
        key->data = talloc_zero_size(key, key->length);
 
        sign_tsig(mem_ctx, key, dns_packet);
 
-#if 1
        NDR_PRINT_DEBUG(dns_name_packet, dns_packet);
        ndr_err = ndr_push_struct_blob(&out, mem_ctx, dns_packet,
                        (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
@@ -276,7 +267,35 @@ int main(int argc, char **argv)
        }
 
        dump_data(1, out.data, out.length);
-#endif
+       req = dns_udp_request_send(mem_ctx, ev, argv[1], out.data, out.length);
+       if (req == NULL) {
+               DEBUG(0, ("Failed to allocate memory for tevent_req\n"));
+               ret = 1;
+               goto error;
+       }
+       if (!tevent_req_poll(req, ev)) {
+               DEBUG(0, ("Error sending dns request\n"));
+               ret = 1;
+               goto error;
+       }
+       w_err = dns_udp_request_recv(req, mem_ctx, &in.data, &in.length);
+       if (!W_ERROR_IS_OK(w_err)) {
+               DEBUG(0, ("Error receiving dns request: %s\n", win_errstr(w_err)));
+               ret = 1;
+               goto error;
+       }
+
+       in_packet = talloc(mem_ctx, struct dns_name_packet);
+
+       ndr_err = ndr_pull_struct_blob(&in, in_packet, in_packet,
+                       (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(0, ("Failed to unmarshall dns_name_packet: %d\n", ndr_err));
+               ret = 1;
+               goto error;
+       }
+
+       NDR_PRINT_DEBUG(dns_name_packet, in_packet);
 
 error:
        return ret;