]> git.ipfire.org Git - people/ms/dnsmasq.git/commitdiff
DNSSEC fix, signed wildcard CNAME to unsigned domain.
authorSimon Kelley <simon@thekelleys.org.uk>
Thu, 16 Jul 2015 21:23:13 +0000 (22:23 +0100)
committerSimon Kelley <simon@thekelleys.org.uk>
Thu, 16 Jul 2015 21:23:13 +0000 (22:23 +0100)
CHANGELOG
src/dnssec.c

index 0eb3c0c987201a2d78f50fde237e90721400e577..7c621e283bd0ab3124515eb2559c4a59139143e8 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,10 @@ version 2.74
            Fix inotify code to handle dangling symlinks better and
            not SEGV in some circumstances.
 
+           DNSSEC fix. In the case of a signed CNAME generated by a
+           wildcard which pointed to an unsigned domain, the wrong
+            status would be logged, and some necessary checks omitted.
+       
 
 version 2.73
             Fix crash at startup when an empty suffix is supplied to
index 52d14548b8e2997660ec98740e8abceffc3d86e8..5fb375c627da17fa6f6ea3e64d4379df779b19a6 100644 (file)
@@ -2112,6 +2112,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char
   unsigned char *p = (unsigned char *)(header+1);
   int type, class, qclass, rdlen, j, rc;
   int cname_count = CNAME_CHAIN;
+  char *wildname;
 
   /* Get question */
   if (!extract_name(header, plen, &p, name, 1, 4))
@@ -2145,7 +2146,46 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char
            return STAT_INSECURE;
          
          /* validate CNAME chain, return if insecure or need more data */
-         rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, NULL, 0, 0, 0);
+         rc = validate_rrset(now, header, plen, class, type, name, keyname, &wildname, NULL, 0, 0, 0);
+          
+         if (rc == STAT_SECURE_WILDCARD)
+           {
+             int nsec_type, nsec_count, i;
+             unsigned char **nsecs;
+
+             /* An attacker can replay a wildcard answer with a different
+                answer and overlay a genuine RR. To prove this
+                hasn't happened, the answer must prove that
+                the genuine record doesn't exist. Check that here. */
+             if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class)))
+               return STAT_BOGUS; /* No NSECs or bad packet */
+             
+             /* Note that we're called here because something didn't validate in validate_reply,
+                so we can't assume that any NSEC records have been validated. We do them by steam here */
+
+             for (i = 0; i < nsec_count; i++)
+               {
+                 unsigned char *p1 = nsecs[i];
+                 
+                 if (!extract_name(header, plen, &p1, daemon->workspacename, 1, 0))
+                   return STAT_BOGUS;
+
+                 rc = validate_rrset(now, header, plen, class, nsec_type, daemon->workspacename, keyname, NULL, NULL, 0, 0, 0);
+
+                 if (rc != STAT_SECURE)
+                   return rc;
+               }
+
+             if (nsec_type == T_NSEC)
+               rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type, NULL);
+             else
+               rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, 
+                                              keyname, name, type, wildname, NULL);
+             
+             if (rc != STAT_SECURE)
+               return rc;
+           }
+         
          if (rc != STAT_SECURE)
            {
              if (rc == STAT_NO_SIG)