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

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