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