Blame SOURCES/dnsmasq-2.79-CVE-2020-25685.patch

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