Hi,

I have a patch for TSIG authentication in libasr.  It is enabled by the "tsig"
keyword in /etc/resolv.conf.  My /etc/resolv.conf looks like this:

search centroid.eu
#nameserver 192.168.34.1
nameserver 200.46.208.61
tsig secret-key.:DONTTRY
lookup file bind

The HMAC over the TSIG is SHA256-HMAC by default but this can be expanded if
willed.

I have tested this by relinking ping and running chrome on websites that I
never visited before, it works.  If you need help setting this up on a BIND
nameserver so that it can recurse a TSIG authenticated lookup, let me know
I can share my example.

The code follows.  If there is an interest for this, I'll clean it up and 
write a manpage, I worked on getting this working as a start.


? asr.patch
Index: asr.c
===================================================================
RCS file: /cvs/src/lib/libc/asr/asr.c,v
retrieving revision 1.50
diff -u -p -u -r1.50 asr.c
--- asr.c       16 Dec 2015 16:32:30 -0000      1.50
+++ asr.c       27 Feb 2016 10:26:33 -0000
@@ -527,6 +527,7 @@ pass0(char **tok, int n, struct asr_ctx 
 {
        int              i, j, d;
        const char      *e;
+       char            *p;
        struct sockaddr_storage ss;
 
        if (!strcmp(tok[0], "nameserver")) {
@@ -548,6 +549,32 @@ pass0(char **tok, int n, struct asr_ctx 
                        return;
                ac->ac_domain = strdup(tok[1]);
 
+       } else if (!strcmp(tok[0], "tsig")) {
+               if (n != 2)
+                       return;
+               if (ac->ac_use_tsig)
+                       return;
+
+               p = strchr(tok[1], ':');
+               if (p == NULL)
+                       return;
+
+               *p = '\0';
+               if (_asr_dname_from_fqdn(tok[1], ac->ac_tsig_key, 
sizeof(ac->ac_tsig_key)) == -1)
+                       return;
+
+               /* RFC 4635 */
+               if (_asr_dname_from_fqdn("hmac-sha256.", ac->ac_dn_algorithm, 
sizeof(ac->ac_dn_algorithm)) == -1)
+                       return;
+
+               p++;
+               ac->ac_use_tsig = 1;
+       
+               ac->ac_dn_algorithm_len = strlen(ac->ac_dn_algorithm);
+               ac->ac_algorithm_size = 32;
+
+               ac->ac_tsig_password = strdup(p);
+               
        } else if (!strcmp(tok[0], "lookup")) {
                /* ensure that each lookup is only given once */
                for (i = 1; i < n; i++)
Index: asr_private.h
===================================================================
RCS file: /cvs/src/lib/libc/asr/asr_private.h,v
retrieving revision 1.38
diff -u -p -u -r1.38 asr_private.h
--- asr_private.h       16 Dec 2015 16:32:30 -0000      1.38
+++ asr_private.h       27 Feb 2016 10:26:33 -0000
@@ -135,7 +135,13 @@ struct asr_ctx {
        int              ac_nstimeout;
        int              ac_nsretries;
        struct sockaddr *ac_ns[ASR_MAXNS];
-
+       /* pjp below */
+       int              ac_use_tsig;
+       char            *ac_tsig_password;
+       char             ac_tsig_key[MAXDNAME];
+       char             ac_dn_algorithm[MAXDNAME];
+       int              ac_dn_algorithm_len;
+       int              ac_algorithm_size;
 };
 
 struct asr {
@@ -301,6 +307,7 @@ __BEGIN_HIDDEN_DECLS
 void _asr_pack_init(struct asr_pack *, char *, size_t);
 int _asr_pack_header(struct asr_pack *, const struct asr_dns_header *);
 int _asr_pack_query(struct asr_pack *, uint16_t, uint16_t, const char *);
+int _asr_tsig_query(struct asr_pack *, const struct asr_dns_header *, struct 
asr_ctx *, const char *, uint16_t);
 void _asr_unpack_init(struct asr_unpack *, const char *, size_t);
 int _asr_unpack_header(struct asr_unpack *, struct asr_dns_header *);
 int _asr_unpack_query(struct asr_unpack *, struct asr_dns_query *);
@@ -308,6 +315,7 @@ int _asr_unpack_rr(struct asr_unpack *, 
 int _asr_sockaddr_from_str(struct sockaddr *, int, const char *);
 ssize_t _asr_dname_from_fqdn(const char *, char *, size_t);
 ssize_t _asr_addr_as_fqdn(const char *, int, char *, size_t);
+void _asr_hmac_sha256(u_char *text, int text_len, u_char *key, int key_len, 
char *digest);
 
 /* asr.c */
 static void *_asr_resolver(void);
Index: asr_utils.c
===================================================================
RCS file: /cvs/src/lib/libc/asr/asr_utils.c,v
retrieving revision 1.13
diff -u -p -u -r1.13 asr_utils.c
--- asr_utils.c 9 Sep 2015 15:49:34 -0000       1.13
+++ asr_utils.c 27 Feb 2016 10:26:34 -0000
@@ -32,6 +32,8 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <sha2.h>
+
 #include "asr_private.h"
 
 static int dname_check_label(const char *, size_t);
@@ -373,6 +375,14 @@ pack_data(struct asr_pack *p, const void
 }
 
 static int
+pack_u32(struct asr_pack *p, uint32_t v)
+{
+       v = htonl(v);
+
+       return (pack_data(p, &v, 4));
+}
+
+static int
 pack_u16(struct asr_pack *p, uint16_t v)
 {
        v = htons(v);
@@ -415,6 +425,89 @@ _asr_pack_query(struct asr_pack *p, uint
 }
 
 int
+_asr_tsig_query(struct asr_pack *p, const struct asr_dns_header *h, struct 
asr_ctx *ac, const char *dname, uint16_t class)
+{
+       char buf[512];
+       int buflen, hlen;
+       int i;
+       uint32_t now;
+       char mac[32];
+       struct asr_pack pseudo, *pp;
+       struct dns_header {
+               uint16_t id;
+               uint16_t query;
+               uint16_t question;
+               uint16_t answer;
+               uint16_t nsrr;
+               uint16_t additional;
+       } *dhdr;
+
+
+       memset(&buf, 0, sizeof(buf));
+       if (p->offset < sizeof(buf))
+               memcpy(&buf, p->buf, p->offset);
+       else
+               return -1;
+
+       hlen = p->offset;
+       now = time(NULL);
+
+       pack_dname(p, ac->ac_tsig_key);         /* key name */
+       pack_u16(p, T_TSIG);                    /* transactional signature */
+       pack_u16(p, C_ANY);                     /* class */
+       pack_u32(p, 0);                         /* ttl */
+       pack_u16(p, ac->ac_dn_algorithm_len + 2 + 4 + 2 + 2 + 
ac->ac_algorithm_size + 2 + 2 + 2 + 1);                           /* rdata len 
*/
+       pack_dname(p, ac->ac_dn_algorithm);     /* algorithm name */
+       pack_u16(p, 0);                         /* time 1 */
+       pack_u32(p, now);                       /* time 2 */
+       pack_u16(p, 300);                       /* fudge */
+       pack_u16(p, ac->ac_algorithm_size);  /* mac size */
+
+       /* start pseudo packet */
+       buflen = p->offset + sizeof(mac) + 6;
+       _asr_pack_init(&pseudo, buf, buflen);
+       pp = &pseudo;
+       pp->offset = hlen;
+
+       /*
+        * libasr has already incremented this in the header but we must
+        * take it out for digesting
+        */
+
+       dhdr = (struct dns_header *)&buf;
+       dhdr->additional = 0;
+
+       pack_dname(pp, ac->ac_tsig_key);        /* key name */
+       pack_u16(pp, C_ANY);                    /* class */
+       pack_u32(pp, 0);                        /* ttl */
+       pack_dname(pp, ac->ac_dn_algorithm);    /* algorithm name */
+       pack_u16(pp, 0);                        /* time 1 */
+       pack_u32(pp, now);                      /* time 2 */
+       pack_u16(pp, 300);                      /* fudge */
+       pack_u16(pp, 0);                        /* error */
+       pack_u16(pp, 0);                        /* other len */
+       /* end of pseudo packet */
+
+#if DEBUG
+       printf("\n");
+       for (i = 0; i < pp->offset; i++) {
+               printf("%02x", buf[i] & 0xff);
+       }
+       printf("\n");
+#endif
+       
+       _asr_hmac_sha256(pp->buf, pp->offset, ac->ac_tsig_password, 
strlen(ac->ac_tsig_password), (char *)&mac);
+
+       pack_data(p, mac, ac->ac_algorithm_size);       /* mac */
+       pack_u16(p, ntohs(h->id));              /* original id */
+       pack_u16(p, 0);         /* error */
+       pack_u16(p, 0);         /* other len */
+
+
+       return (p->err) ? (-1) : (0);
+}
+
+int
 _asr_sockaddr_from_str(struct sockaddr *sa, int family, const char *str)
 {
        struct in_addr           ina;
@@ -543,4 +636,56 @@ _asr_addr_as_fqdn(const char *addr, int 
                return (-1);
        }
        return (0);
+}
+
+void
+_asr_hmac_sha256(u_char *text, int text_len, u_char *key, int key_len, char 
*digest)
+{
+        SHA2_CTX context;
+        unsigned char k_ipad[65];    /* inner padding -
+                                      * key XORd with ipad
+                                      */
+        unsigned char k_opad[65];    /* outer padding -
+                                      * key XORd with opad
+                                      */
+        unsigned char tk[32];
+        int i;
+
+        if (key_len > 64) {
+
+                SHA2_CTX      tctx;
+
+                SHA256Init(&tctx);
+                SHA256Update(&tctx, key, key_len);
+                SHA256Final(tk, &tctx);
+
+                key = tk;
+                key_len = 32;
+        }
+
+        /* start out by storing key in pads */
+        bzero( k_ipad, sizeof k_ipad);
+        bzero( k_opad, sizeof k_opad);
+        bcopy( key, k_ipad, key_len);
+        bcopy( key, k_opad, key_len);
+
+        /* XOR key with ipad and opad values */
+        for (i=0; i<64; i++) {
+                k_ipad[i] ^= 0x36;
+                k_opad[i] ^= 0x5c;
+        }
+        /*
+         * perform inner SHA256
+         */
+        SHA256Init(&context);
+        SHA256Update(&context, k_ipad, 64);
+        SHA256Update(&context, text, text_len);
+        SHA256Final(digest, &context);
+        /*
+         * perform outer SHA256
+         */
+        SHA256Init(&context);
+        SHA256Update(&context, k_opad, 64);
+        SHA256Update(&context, digest, 32);
+        SHA256Final(digest, &context);
 }
Index: res_mkquery.c
===================================================================
RCS file: /cvs/src/lib/libc/asr/res_mkquery.c,v
retrieving revision 1.9
diff -u -p -u -r1.9 res_mkquery.c
--- res_mkquery.c       9 Sep 2015 15:49:34 -0000       1.9
+++ res_mkquery.c       27 Feb 2016 10:26:34 -0000
@@ -62,9 +62,16 @@ res_mkquery(int op, const char *dname, i
                h.flags |= RD_MASK;
        h.qdcount = 1;
 
+       if (ac->ac_use_tsig) {
+               h.arcount = 1;
+       }
+
        _asr_pack_init(&p, buf, buflen);
        _asr_pack_header(&p, &h);
        _asr_pack_query(&p, type, class, dn);
+
+       if (ac->ac_use_tsig)
+               _asr_tsig_query(&p, &h, ac, dn, class);
 
        _asr_ctx_unref(ac);
 
Index: res_send_async.c
===================================================================
RCS file: /cvs/src/lib/libc/asr/res_send_async.c,v
retrieving revision 1.29
diff -u -p -u -r1.29 res_send_async.c
--- res_send_async.c    23 Oct 2015 00:52:09 -0000      1.29
+++ res_send_async.c    27 Feb 2016 10:26:34 -0000
@@ -378,6 +378,10 @@ setup_query(struct asr_query *as, const 
                h.flags |= RD_MASK;
        h.qdcount = 1;
 
+        if (as->as_ctx->ac_use_tsig) {
+                h.arcount = 1;
+        }
+
        _asr_pack_init(&p, as->as.dns.obuf, as->as.dns.obufsize);
        _asr_pack_header(&p, &h);
        _asr_pack_query(&p, type, class, dname);
@@ -386,6 +390,9 @@ setup_query(struct asr_query *as, const 
                errno = EINVAL;
                return (-1);
        }
+
+        if (as->as_ctx->ac_use_tsig)
+                _asr_tsig_query(&p, &h, as->as_ctx, dname, class);
 
        /* Remember the parameters. */
        as->as.dns.reqid = h.id;

Reply via email to