ed3ca9
From 6cbbae54c9232f182cc76f05962a07244d748b75 Mon Sep 17 00:00:00 2001
ed3ca9
From: Simon Kelley <simon@thekelleys.org.uk>
ed3ca9
Date: Thu, 12 Nov 2020 22:06:07 +0000
ed3ca9
Subject: [PATCH 3/4] Use SHA-256 to provide security against DNS cache
ed3ca9
 poisoning.
ed3ca9
ed3ca9
Use the SHA-256 hash function to verify that DNS answers
ed3ca9
received are for the questions originally asked. This replaces
ed3ca9
the slightly insecure SHA-1 (when compiled with DNSSEC) or
ed3ca9
the very insecure CRC32 (otherwise). Refer: CERT VU#434904.
ed3ca9
---
ed3ca9
 Makefile             |   3 +-
ed3ca9
 bld/Android.mk       |   3 +-
ed3ca9
 src/dnsmasq.h        |  11 +-
ed3ca9
 src/dnssec.c         |  31 -----
ed3ca9
 src/forward.c        |  43 ++-----
ed3ca9
 src/hash_questions.c | 281 +++++++++++++++++++++++++++++++++++++++++++
ed3ca9
 src/rfc1035.c        |  49 --------
ed3ca9
 7 files changed, 297 insertions(+), 124 deletions(-)
ed3ca9
 create mode 100644 src/hash_questions.c
ed3ca9
ed3ca9
diff --git a/Makefile b/Makefile
ed3ca9
index 98ec760..cbbe5d7 100644
ed3ca9
--- a/Makefile
ed3ca9
+++ b/Makefile
ed3ca9
@@ -76,7 +76,8 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
ed3ca9
        helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
ed3ca9
        dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
ed3ca9
        domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
ed3ca9
-       poll.o rrfilter.o edns0.o arp.o crypto.o
ed3ca9
+       poll.o rrfilter.o edns0.o arp.o crypto.o \
ed3ca9
+       hash_questions.o
ed3ca9
 
ed3ca9
 hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
ed3ca9
        dns-protocol.h radv-protocol.h ip6addr.h
ed3ca9
diff --git a/bld/Android.mk b/bld/Android.mk
ed3ca9
index 80ec842..2db29c1 100644
ed3ca9
--- a/bld/Android.mk
ed3ca9
+++ b/bld/Android.mk
ed3ca9
@@ -10,7 +10,8 @@ LOCAL_SRC_FILES :=  bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
ed3ca9
 		    dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
ed3ca9
 		    radv.c slaac.c auth.c ipset.c domain.c \
ed3ca9
 	            dnssec.c dnssec-openssl.c blockdata.c tables.c \
ed3ca9
-		    loop.c inotify.c poll.c rrfilter.c edns0.c arp.c crypto.c
ed3ca9
+		    loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
ed3ca9
+		    crypto.c hash_questions.c
ed3ca9
 
ed3ca9
 LOCAL_MODULE := dnsmasq
ed3ca9
 
ed3ca9
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
ed3ca9
index 6773b69..f31503d 100644
ed3ca9
--- a/src/dnsmasq.h
ed3ca9
+++ b/src/dnsmasq.h
ed3ca9
@@ -615,11 +615,7 @@ struct hostsfile {
ed3ca9
 #define FREC_TEST_PKTSZ       256
ed3ca9
 #define FREC_HAS_EXTRADATA    512        
ed3ca9
 
ed3ca9
-#ifdef HAVE_DNSSEC
ed3ca9
-#define HASH_SIZE 20 /* SHA-1 digest size */
ed3ca9
-#else
ed3ca9
-#define HASH_SIZE sizeof(int)
ed3ca9
-#endif
ed3ca9
+#define HASH_SIZE 32 /* SHA-256 digest size */
ed3ca9
 
ed3ca9
 struct frec {
ed3ca9
   union mysockaddr source;
ed3ca9
@@ -1156,7 +1152,6 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
ed3ca9
 			     struct bogus_addr *baddr, time_t now);
ed3ca9
 int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
ed3ca9
 int check_for_local_domain(char *name, time_t now);
ed3ca9
-unsigned int questions_crc(struct dns_header *header, size_t plen, char *name);
ed3ca9
 size_t resize_packet(struct dns_header *header, size_t plen, 
ed3ca9
 		  unsigned char *pheader, size_t hlen);
ed3ca9
 int add_resource_record(struct dns_header *header, char *limit, int *truncp,
ed3ca9
@@ -1184,9 +1179,11 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
ed3ca9
 			  int check_unsigned, int *neganswer, int *nons);
ed3ca9
 int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
ed3ca9
 size_t filter_rrsigs(struct dns_header *header, size_t plen);
ed3ca9
-unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
ed3ca9
 int setup_timestamp(void);
ed3ca9
 
ed3ca9
+/* hash_questions.c */
ed3ca9
+unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name);
ed3ca9
+
ed3ca9
 /* crypto.c */
ed3ca9
 const struct nettle_hash *hash_find(char *name);
ed3ca9
 int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp);
ed3ca9
diff --git a/src/dnssec.c b/src/dnssec.c
ed3ca9
index 0c703ac..b2dda1b 100644
ed3ca9
--- a/src/dnssec.c
ed3ca9
+++ b/src/dnssec.c
ed3ca9
@@ -2095,35 +2095,4 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
ed3ca9
   return ret;
ed3ca9
 }
ed3ca9
 
ed3ca9
-unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
ed3ca9
-{
ed3ca9
-  int q;
ed3ca9
-  unsigned int len;
ed3ca9
-  unsigned char *p = (unsigned char *)(header+1);
ed3ca9
-  const struct nettle_hash *hash;
ed3ca9
-  void *ctx;
ed3ca9
-  unsigned char *digest;
ed3ca9
-  
ed3ca9
-  if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
ed3ca9
-    return NULL;
ed3ca9
-  
ed3ca9
-  for (q = ntohs(header->qdcount); q != 0; q--) 
ed3ca9
-    {
ed3ca9
-      if (!extract_name(header, plen, &p, name, 1, 4))
ed3ca9
-	break; /* bad packet */
ed3ca9
-      
ed3ca9
-      len = to_wire(name);
ed3ca9
-      hash->update(ctx, len, (unsigned char *)name);
ed3ca9
-      /* CRC the class and type as well */
ed3ca9
-      hash->update(ctx, 4, p);
ed3ca9
-
ed3ca9
-      p += 4;
ed3ca9
-      if (!CHECK_LEN(header, p, plen, 0))
ed3ca9
-	break; /* bad packet */
ed3ca9
-    }
ed3ca9
-  
ed3ca9
-  hash->digest(ctx, hash->digest_size, digest);
ed3ca9
-  return digest;
ed3ca9
-}
ed3ca9
-
ed3ca9
 #endif /* HAVE_DNSSEC */
ed3ca9
diff --git a/src/forward.c b/src/forward.c
ed3ca9
index 85eab27..7ffcaf7 100644
ed3ca9
--- a/src/forward.c
ed3ca9
+++ b/src/forward.c
ed3ca9
@@ -239,19 +239,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
ed3ca9
   struct all_addr *addrp = NULL;
ed3ca9
   unsigned int flags = 0;
ed3ca9
   struct server *start = NULL;
ed3ca9
-#ifdef HAVE_DNSSEC
ed3ca9
   void *hash = hash_questions(header, plen, daemon->namebuff);
ed3ca9
+#ifdef HAVE_DNSSEC
ed3ca9
   int do_dnssec = 0;
ed3ca9
-#else
ed3ca9
-  unsigned int crc = questions_crc(header, plen, daemon->namebuff);
ed3ca9
-  void *hash = &crc;
ed3ca9
 #endif
ed3ca9
  unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
ed3ca9
 
ed3ca9
  (void)do_bit;
ed3ca9
 
ed3ca9
   /* may be no servers available. */
ed3ca9
-  if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
ed3ca9
+  if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))
ed3ca9
     {
ed3ca9
       /* If we didn't get an answer advertising a maximal packet in EDNS,
ed3ca9
 	 fall back to 1280, which should work everywhere on IPv6.
ed3ca9
@@ -741,9 +738,6 @@ void reply_query(int fd, int family, time_t now)
ed3ca9
   size_t nn;
ed3ca9
   struct server *server;
ed3ca9
   void *hash;
ed3ca9
-#ifndef HAVE_DNSSEC
ed3ca9
-  unsigned int crc;
ed3ca9
-#endif
ed3ca9
 
ed3ca9
   /* packet buffer overwritten */
ed3ca9
   daemon->srv_save = NULL;
ed3ca9
@@ -773,12 +767,7 @@ void reply_query(int fd, int family, time_t now)
ed3ca9
   if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
ed3ca9
     server->edns_pktsz = daemon->edns_pktsz;
ed3ca9
 
ed3ca9
-#ifdef HAVE_DNSSEC
ed3ca9
   hash = hash_questions(header, n, daemon->namebuff);
ed3ca9
-#else
ed3ca9
-  hash = &crc;
ed3ca9
-  crc = questions_crc(header, n, daemon->namebuff);
ed3ca9
-#endif
ed3ca9
   
ed3ca9
   if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
ed3ca9
     return;
ed3ca9
@@ -1006,8 +995,7 @@ void reply_query(int fd, int family, time_t now)
ed3ca9
 			  nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
ed3ca9
 						     daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
ed3ca9
 			}
ed3ca9
-		      if ((hash = hash_questions(header, nn, daemon->namebuff)))
ed3ca9
-			memcpy(new->hash, hash, HASH_SIZE);
ed3ca9
+		      memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
ed3ca9
 		      new->new_id = get_id();
ed3ca9
 		      header->id = htons(new->new_id);
ed3ca9
 		      /* Save query for retransmission */
ed3ca9
@@ -1840,15 +1828,9 @@ unsigned char *tcp_request(int confd, time_t now,
ed3ca9
 	      if (!flags && last_server)
ed3ca9
 		{
ed3ca9
 		  struct server *firstsendto = NULL;
ed3ca9
-#ifdef HAVE_DNSSEC
ed3ca9
-		  unsigned char *newhash, hash[HASH_SIZE];
ed3ca9
-		  if ((newhash = hash_questions(header, (unsigned int)size, daemon->namebuff)))
ed3ca9
-		    memcpy(hash, newhash, HASH_SIZE);
ed3ca9
-		  else
ed3ca9
-		    memset(hash, 0, HASH_SIZE);
ed3ca9
-#else
ed3ca9
-		  unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
ed3ca9
-#endif		  
ed3ca9
+		  unsigned char hash[HASH_SIZE];
ed3ca9
+		  memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
ed3ca9
+
ed3ca9
 		  /* Loop round available servers until we succeed in connecting to one.
ed3ca9
 		     Note that this code subtly ensures that consecutive queries on this connection
ed3ca9
 		     which can go to the same server, do so. */
ed3ca9
@@ -1973,20 +1955,11 @@ unsigned char *tcp_request(int confd, time_t now,
ed3ca9
 		      /* If the crc of the question section doesn't match the crc we sent, then
ed3ca9
 			 someone might be attempting to insert bogus values into the cache by 
ed3ca9
 			 sending replies containing questions and bogus answers. */
ed3ca9
-#ifdef HAVE_DNSSEC
ed3ca9
-		      newhash = hash_questions(header, (unsigned int)m, daemon->namebuff);
ed3ca9
-		      if (!newhash || memcmp(hash, newhash, HASH_SIZE) != 0)
ed3ca9
+		      if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
ed3ca9
 			{ 
ed3ca9
 			  m = 0;
ed3ca9
 			  break;
ed3ca9
 			}
ed3ca9
-#else			  
ed3ca9
-		      if (crc != questions_crc(header, (unsigned int)m, daemon->namebuff))
ed3ca9
-			{
ed3ca9
-			  m = 0;
ed3ca9
-			  break;
ed3ca9
-			}
ed3ca9
-#endif
ed3ca9
 
ed3ca9
 		      m = process_reply(header, now, last_server, (unsigned int)m, 
ed3ca9
 					option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
ed3ca9
@@ -2201,7 +2174,7 @@ static struct frec *lookup_frec(unsigned short id, int fd, int family, void *has
ed3ca9
 
ed3ca9
   for(f = daemon->frec_list; f; f = f->next)
ed3ca9
     if (f->sentto && f->new_id == id && 
ed3ca9
-	(!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
ed3ca9
+	(memcmp(hash, f->hash, HASH_SIZE) == 0))
ed3ca9
       {
ed3ca9
 	/* sent from random port */
ed3ca9
 	if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
ed3ca9
diff --git a/src/hash_questions.c b/src/hash_questions.c
ed3ca9
new file mode 100644
ed3ca9
index 0000000..ae112ac
ed3ca9
--- /dev/null
ed3ca9
+++ b/src/hash_questions.c
ed3ca9
@@ -0,0 +1,281 @@
ed3ca9
+/* Copyright (c) 2012-2020 Simon Kelley
ed3ca9
+
ed3ca9
+   This program is free software; you can redistribute it and/or modify
ed3ca9
+   it under the terms of the GNU General Public License as published by
ed3ca9
+   the Free Software Foundation; version 2 dated June, 1991, or
ed3ca9
+   (at your option) version 3 dated 29 June, 2007.
ed3ca9
+
ed3ca9
+   This program is distributed in the hope that it will be useful,
ed3ca9
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
ed3ca9
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ed3ca9
+   GNU General Public License for more details.
ed3ca9
+
ed3ca9
+   You should have received a copy of the GNU General Public License
ed3ca9
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
ed3ca9
+*/
ed3ca9
+
ed3ca9
+
ed3ca9
+/* Hash the question section. This is used to safely detect query 
ed3ca9
+   retransmission and to detect answers to questions we didn't ask, which 
ed3ca9
+   might be poisoning attacks. Note that we decode the name rather 
ed3ca9
+   than CRC the raw bytes, since replies might be compressed differently. 
ed3ca9
+   We ignore case in the names for the same reason. 
ed3ca9
+
ed3ca9
+   The hash used is SHA-256. If we're building with DNSSEC support,
ed3ca9
+   we use the Nettle cypto library. If not, we prefer not to
ed3ca9
+   add a dependency on Nettle, and use a stand-alone implementaion. 
ed3ca9
+*/
ed3ca9
+
ed3ca9
+#include "dnsmasq.h"
ed3ca9
+
ed3ca9
+#ifdef HAVE_DNSSEC
ed3ca9
+unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
ed3ca9
+{
ed3ca9
+  int q;
ed3ca9
+  unsigned char *p = (unsigned char *)(header+1);
ed3ca9
+  const struct nettle_hash *hash;
ed3ca9
+  void *ctx;
ed3ca9
+  unsigned char *digest;
ed3ca9
+  
ed3ca9
+  if (!(hash = hash_find("sha256")) || !hash_init(hash, &ctx, &digest))
ed3ca9
+    {
ed3ca9
+      /* don't think this can ever happen. */
ed3ca9
+      static unsigned char dummy[HASH_SIZE];
ed3ca9
+      static int warned = 0;
ed3ca9
+
ed3ca9
+      if (warned)
ed3ca9
+	my_syslog(LOG_ERR, _("Failed to create SHA-256 hash object"));
ed3ca9
+      warned = 1;
ed3ca9
+     
ed3ca9
+      return dummy;
ed3ca9
+    }
ed3ca9
+  
ed3ca9
+  for (q = ntohs(header->qdcount); q != 0; q--) 
ed3ca9
+    {
ed3ca9
+      char *cp, c;
ed3ca9
+
ed3ca9
+      if (!extract_name(header, plen, &p, name, 1, 4))
ed3ca9
+	break; /* bad packet */
ed3ca9
+
ed3ca9
+      for (cp = name; (c = *cp); cp++)
ed3ca9
+	 if (c >= 'A' && c <= 'Z')
ed3ca9
+	   *cp += 'a' - 'A';
ed3ca9
+
ed3ca9
+      hash->update(ctx, cp - name, (unsigned char *)name);
ed3ca9
+      /* CRC the class and type as well */
ed3ca9
+      hash->update(ctx, 4, p);
ed3ca9
+
ed3ca9
+      p += 4;
ed3ca9
+      if (!CHECK_LEN(header, p, plen, 0))
ed3ca9
+	break; /* bad packet */
ed3ca9
+    }
ed3ca9
+  
ed3ca9
+  hash->digest(ctx, hash->digest_size, digest);
ed3ca9
+  return digest;
ed3ca9
+}
ed3ca9
+
ed3ca9
+#else /* HAVE_DNSSEC */
ed3ca9
+
ed3ca9
+#define SHA256_BLOCK_SIZE 32            // SHA256 outputs a 32 byte digest
ed3ca9
+typedef unsigned char BYTE;             // 8-bit byte
ed3ca9
+typedef unsigned int  WORD;             // 32-bit word, change to "long" for 16-bit machines
ed3ca9
+
ed3ca9
+typedef struct {
ed3ca9
+  BYTE data[64];
ed3ca9
+  WORD datalen;
ed3ca9
+  unsigned long long bitlen;
ed3ca9
+  WORD state[8];
ed3ca9
+} SHA256_CTX;
ed3ca9
+
ed3ca9
+static void sha256_init(SHA256_CTX *ctx);
ed3ca9
+static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
ed3ca9
+static void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
ed3ca9
+
ed3ca9
+
ed3ca9
+unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
ed3ca9
+{
ed3ca9
+  int q;
ed3ca9
+  unsigned char *p = (unsigned char *)(header+1);
ed3ca9
+  SHA256_CTX ctx;
ed3ca9
+  static BYTE digest[SHA256_BLOCK_SIZE];
ed3ca9
+  
ed3ca9
+  sha256_init(&ctx;;
ed3ca9
+    
ed3ca9
+  for (q = ntohs(header->qdcount); q != 0; q--) 
ed3ca9
+    {
ed3ca9
+      char *cp, c;
ed3ca9
+
ed3ca9
+      if (!extract_name(header, plen, &p, name, 1, 4))
ed3ca9
+	break; /* bad packet */
ed3ca9
+
ed3ca9
+      for (cp = name; (c = *cp); cp++)
ed3ca9
+	 if (c >= 'A' && c <= 'Z')
ed3ca9
+	   *cp += 'a' - 'A';
ed3ca9
+
ed3ca9
+      sha256_update(&ctx, (BYTE *)name, cp - name);
ed3ca9
+      /* CRC the class and type as well */
ed3ca9
+      sha256_update(&ctx, (BYTE *)p, 4);
ed3ca9
+
ed3ca9
+      p += 4;
ed3ca9
+      if (!CHECK_LEN(header, p, plen, 0))
ed3ca9
+	break; /* bad packet */
ed3ca9
+    }
ed3ca9
+  
ed3ca9
+  sha256_final(&ctx, digest);
ed3ca9
+  return (unsigned char *)digest;
ed3ca9
+}
ed3ca9
+
ed3ca9
+/* Code from here onwards comes from https://github.com/B-Con/crypto-algorithms
ed3ca9
+   and was written by Brad Conte (brad@bradconte.com), to whom all credit is given.
ed3ca9
+
ed3ca9
+   This code is in the public domain, and the copyright notice at the head of this 
ed3ca9
+   file does not apply to it.
ed3ca9
+*/
ed3ca9
+
ed3ca9
+
ed3ca9
+/****************************** MACROS ******************************/
ed3ca9
+#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
ed3ca9
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
ed3ca9
+
ed3ca9
+#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
ed3ca9
+#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
ed3ca9
+#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
ed3ca9
+#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
ed3ca9
+#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
ed3ca9
+#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
ed3ca9
+
ed3ca9
+/**************************** VARIABLES *****************************/
ed3ca9
+static const WORD k[64] = {
ed3ca9
+			   0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
ed3ca9
+			   0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
ed3ca9
+			   0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
ed3ca9
+			   0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
ed3ca9
+			   0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
ed3ca9
+			   0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
ed3ca9
+			   0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
ed3ca9
+			   0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
ed3ca9
+};
ed3ca9
+
ed3ca9
+/*********************** FUNCTION DEFINITIONS ***********************/
ed3ca9
+static void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
ed3ca9
+{
ed3ca9
+  WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
ed3ca9
+  
ed3ca9
+  for (i = 0, j = 0; i < 16; ++i, j += 4)
ed3ca9
+    m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
ed3ca9
+  for ( ; i < 64; ++i)
ed3ca9
+    m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
ed3ca9
+
ed3ca9
+  a = ctx->state[0];
ed3ca9
+  b = ctx->state[1];
ed3ca9
+  c = ctx->state[2];
ed3ca9
+  d = ctx->state[3];
ed3ca9
+  e = ctx->state[4];
ed3ca9
+  f = ctx->state[5];
ed3ca9
+  g = ctx->state[6];
ed3ca9
+  h = ctx->state[7];
ed3ca9
+
ed3ca9
+  for (i = 0; i < 64; ++i)
ed3ca9
+    {
ed3ca9
+      t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
ed3ca9
+      t2 = EP0(a) + MAJ(a,b,c);
ed3ca9
+      h = g;
ed3ca9
+      g = f;
ed3ca9
+      f = e;
ed3ca9
+      e = d + t1;
ed3ca9
+      d = c;
ed3ca9
+      c = b;
ed3ca9
+      b = a;
ed3ca9
+      a = t1 + t2;
ed3ca9
+    }
ed3ca9
+  
ed3ca9
+  ctx->state[0] += a;
ed3ca9
+  ctx->state[1] += b;
ed3ca9
+  ctx->state[2] += c;
ed3ca9
+  ctx->state[3] += d;
ed3ca9
+  ctx->state[4] += e;
ed3ca9
+  ctx->state[5] += f;
ed3ca9
+  ctx->state[6] += g;
ed3ca9
+  ctx->state[7] += h;
ed3ca9
+}
ed3ca9
+
ed3ca9
+static void sha256_init(SHA256_CTX *ctx)
ed3ca9
+{
ed3ca9
+  ctx->datalen = 0;
ed3ca9
+  ctx->bitlen = 0;
ed3ca9
+  ctx->state[0] = 0x6a09e667;
ed3ca9
+  ctx->state[1] = 0xbb67ae85;
ed3ca9
+  ctx->state[2] = 0x3c6ef372;
ed3ca9
+  ctx->state[3] = 0xa54ff53a;
ed3ca9
+  ctx->state[4] = 0x510e527f;
ed3ca9
+  ctx->state[5] = 0x9b05688c;
ed3ca9
+  ctx->state[6] = 0x1f83d9ab;
ed3ca9
+  ctx->state[7] = 0x5be0cd19;
ed3ca9
+}
ed3ca9
+
ed3ca9
+static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
ed3ca9
+{
ed3ca9
+  WORD i;
ed3ca9
+  
ed3ca9
+  for (i = 0; i < len; ++i)
ed3ca9
+    {
ed3ca9
+      ctx->data[ctx->datalen] = data[i];
ed3ca9
+      ctx->datalen++;
ed3ca9
+      if (ctx->datalen == 64) {
ed3ca9
+	sha256_transform(ctx, ctx->data);
ed3ca9
+	ctx->bitlen += 512;
ed3ca9
+	ctx->datalen = 0;
ed3ca9
+      }
ed3ca9
+    }
ed3ca9
+}
ed3ca9
+
ed3ca9
+static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
ed3ca9
+{
ed3ca9
+  WORD i;
ed3ca9
+  
ed3ca9
+  i = ctx->datalen;
ed3ca9
+
ed3ca9
+  // Pad whatever data is left in the buffer.
ed3ca9
+  if (ctx->datalen < 56)
ed3ca9
+    {
ed3ca9
+      ctx->data[i++] = 0x80;
ed3ca9
+      while (i < 56)
ed3ca9
+	ctx->data[i++] = 0x00;
ed3ca9
+    }
ed3ca9
+  else
ed3ca9
+    {
ed3ca9
+      ctx->data[i++] = 0x80;
ed3ca9
+      while (i < 64)
ed3ca9
+	ctx->data[i++] = 0x00;
ed3ca9
+      sha256_transform(ctx, ctx->data);
ed3ca9
+      memset(ctx->data, 0, 56);
ed3ca9
+    }
ed3ca9
+  
ed3ca9
+  // Append to the padding the total message's length in bits and transform.
ed3ca9
+  ctx->bitlen += ctx->datalen * 8;
ed3ca9
+  ctx->data[63] = ctx->bitlen;
ed3ca9
+  ctx->data[62] = ctx->bitlen >> 8;
ed3ca9
+  ctx->data[61] = ctx->bitlen >> 16;
ed3ca9
+  ctx->data[60] = ctx->bitlen >> 24;
ed3ca9
+  ctx->data[59] = ctx->bitlen >> 32;
ed3ca9
+  ctx->data[58] = ctx->bitlen >> 40;
ed3ca9
+  ctx->data[57] = ctx->bitlen >> 48;
ed3ca9
+  ctx->data[56] = ctx->bitlen >> 56;
ed3ca9
+  sha256_transform(ctx, ctx->data);
ed3ca9
+  
ed3ca9
+  // Since this implementation uses little endian byte ordering and SHA uses big endian,
ed3ca9
+  // reverse all the bytes when copying the final state to the output hash.
ed3ca9
+  for (i = 0; i < 4; ++i)
ed3ca9
+    {
ed3ca9
+      hash[i]      = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
ed3ca9
+      hash[i + 4]  = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
ed3ca9
+      hash[i + 8]  = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
ed3ca9
+      hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
ed3ca9
+      hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
ed3ca9
+      hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
ed3ca9
+      hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
ed3ca9
+      hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
ed3ca9
+    }
ed3ca9
+}
ed3ca9
+
ed3ca9
+#endif
ed3ca9
diff --git a/src/rfc1035.c b/src/rfc1035.c
ed3ca9
index b078b59..d413f58 100644
ed3ca9
--- a/src/rfc1035.c
ed3ca9
+++ b/src/rfc1035.c
ed3ca9
@@ -335,55 +335,6 @@ unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *h
ed3ca9
   return ansp;
ed3ca9
 }
ed3ca9
 
ed3ca9
-/* CRC the question section. This is used to safely detect query 
ed3ca9
-   retransmission and to detect answers to questions we didn't ask, which 
ed3ca9
-   might be poisoning attacks. Note that we decode the name rather 
ed3ca9
-   than CRC the raw bytes, since replies might be compressed differently. 
ed3ca9
-   We ignore case in the names for the same reason. Return all-ones
ed3ca9
-   if there is not question section. */
ed3ca9
-#ifndef HAVE_DNSSEC
ed3ca9
-unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
ed3ca9
-{
ed3ca9
-  int q;
ed3ca9
-  unsigned int crc = 0xffffffff;
ed3ca9
-  unsigned char *p1, *p = (unsigned char *)(header+1);
ed3ca9
-
ed3ca9
-  for (q = ntohs(header->qdcount); q != 0; q--) 
ed3ca9
-    {
ed3ca9
-      if (!extract_name(header, plen, &p, name, 1, 4))
ed3ca9
-	return crc; /* bad packet */
ed3ca9
-      
ed3ca9
-      for (p1 = (unsigned char *)name; *p1; p1++)
ed3ca9
-	{
ed3ca9
-	  int i = 8;
ed3ca9
-	  char c = *p1;
ed3ca9
-
ed3ca9
-	  if (c >= 'A' && c <= 'Z')
ed3ca9
-	    c += 'a' - 'A';
ed3ca9
-
ed3ca9
-	  crc ^= c << 24;
ed3ca9
-	  while (i--)
ed3ca9
-	    crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
ed3ca9
-	}
ed3ca9
-      
ed3ca9
-      /* CRC the class and type as well */
ed3ca9
-      for (p1 = p; p1 < p+4; p1++)
ed3ca9
-	{
ed3ca9
-	  int i = 8;
ed3ca9
-	  crc ^= *p1 << 24;
ed3ca9
-	  while (i--)
ed3ca9
-	    crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
ed3ca9
-	}
ed3ca9
-
ed3ca9
-      p += 4;
ed3ca9
-      if (!CHECK_LEN(header, p, plen, 0))
ed3ca9
-	return crc; /* bad packet */
ed3ca9
-    }
ed3ca9
-
ed3ca9
-  return crc;
ed3ca9
-}
ed3ca9
-#endif
ed3ca9
-
ed3ca9
 size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
ed3ca9
 {
ed3ca9
   unsigned char *ansp = skip_questions(header, plen);
ed3ca9
-- 
ed3ca9
2.26.2
ed3ca9