@@ -90,6 +90,34 @@ public ValUtils() {
9090 this .verifier = new DnsSecVerifier ();
9191 }
9292
93+ /**
94+ * Set the owner name of NSEC RRsets to the canonical name, i.e. the name
95+ * that is <b>not</b> expanded from a wildcard label.
96+ * @param set The RRset to canonicalize.
97+ * @param sig The signature that validated this RRset.
98+ */
99+ public static void setCanonicalNsecOwner (SRRset set , RRSIGRecord sig ) {
100+ if (set .getType () != Type .NSEC ) {
101+ return ;
102+ }
103+
104+ Record nsec = set .first ();
105+ int fqdnLabelCount = nsec .getName ().labels () - 1 ; // don't count the root label
106+ if (nsec .getName ().isWild ()) {
107+ --fqdnLabelCount ; // don't count the wildcard label
108+ }
109+
110+ if (sig .getLabels () == fqdnLabelCount ) {
111+ set .setName (nsec .getName ());
112+ }
113+ else if (sig .getLabels () < fqdnLabelCount ) {
114+ set .setName (nsec .getName ().wild (sig .getSigner ().labels () - sig .getLabels ()));
115+ }
116+ else {
117+ throw new IllegalArgumentException ("invalid nsec record" );
118+ }
119+ }
120+
93121 /**
94122 * Initialize the module. The recognized configuration value are
95123 * <ul>
@@ -445,13 +473,14 @@ public static boolean strictSubdomain(Name domain1, Name domain2) {
445473 * {@link NSECRecord#getNext()}).
446474 *
447475 * @param domain The name for which the closest encloser is queried.
448- * @param nsec The covering {@link NSECRecord} to check.
476+ * @param owner The beginning of the covering {@link Name} to check.
477+ * @param next The end of the covering {@link Name} to check.
449478 * @return The closest encloser name of <code>domain</code> as defined by
450- * < code>nsec</ code> .
479+ * {@ code owner} and {@ code next} .
451480 */
452- public static Name closestEncloser (Name domain , NSECRecord nsec ) {
453- Name n1 = longestCommonName (domain , nsec . getName () );
454- Name n2 = longestCommonName (domain , nsec . getNext () );
481+ public static Name closestEncloser (Name domain , Name owner , Name next ) {
482+ Name n1 = longestCommonName (domain , owner );
483+ Name n2 = longestCommonName (domain , next );
455484
456485 return (n1 .labels () > n2 .labels ()) ? n1 : n2 ;
457486 }
@@ -462,28 +491,29 @@ public static Name closestEncloser(Name domain, NSECRecord nsec) {
462491 *
463492 * @param domain The name for which the wildcard closest encloser is
464493 * demanded.
494+ * @param set The RRset containing {@code nsec} to check.
465495 * @param nsec The covering NSEC that defines the encloser.
466496 * @return The wildcard closest encloser name of <code>domain</code> as
467497 * defined by <code>nsec</code>.
468498 * @throws NameTooLongException If adding the wildcard label to the closest
469499 * encloser results in an invalid name.
470500 */
471- public static Name nsecWildcard (Name domain , NSECRecord nsec ) throws NameTooLongException {
472- Name origin = closestEncloser (domain , nsec );
501+ public static Name nsecWildcard (Name domain , SRRset set , NSECRecord nsec ) throws NameTooLongException {
502+ Name origin = closestEncloser (domain , set . getName (), nsec . getNext () );
473503 return Name .concatenate (WILDCARD , origin );
474504 }
475505
476506 /**
477507 * Determine if the given NSEC proves a NameError (NXDOMAIN) for a given
478508 * qname.
479509 *
510+ * @param set The RRset that contains the NSEC.
480511 * @param nsec The NSEC to check.
481512 * @param qname The qname to check against.
482- * @param signerName The signer of the NSEC RRset.
483513 * @return true if the NSEC proves the condition.
484514 */
485- public static boolean nsecProvesNameError (NSECRecord nsec , Name qname , Name signerName ) {
486- Name owner = nsec .getName ();
515+ public static boolean nsecProvesNameError (SRRset set , NSECRecord nsec , Name qname ) {
516+ Name owner = set .getName ();
487517 Name next = nsec .getNext ();
488518
489519 // If NSEC owner == qname, then this NSEC proves that qname exists.
@@ -492,7 +522,7 @@ public static boolean nsecProvesNameError(NSECRecord nsec, Name qname, Name sign
492522 }
493523
494524 // deny overreaching NSECs
495- if (!next .subdomain (signerName )) {
525+ if (!next .subdomain (set . getSignerName () )) {
496526 return false ;
497527 }
498528
@@ -539,29 +569,25 @@ else if (owner.compareTo(next) > 0) {
539569 * Determine if a NSEC record proves the non-existence of a wildcard that
540570 * could have produced qname.
541571 *
542- * @param nsec The nsec to check.
572+ * @param set The RRset of the NSEC record.
573+ * @param nsec The nsec record to check.
543574 * @param qname The qname to check against.
544- * @param signerName The signer of the NSEC RRset.
545575 * @return true if the NSEC proves the condition.
546576 */
547- public static boolean nsecProvesNoWC (NSECRecord nsec , Name qname , Name signerName ) {
548- int qnameLabels = qname .labels ();
549- Name ce = closestEncloser (qname , nsec );
550- int ceLabels = ce .labels ();
551-
552- for (int i = qnameLabels - ceLabels ; i > 0 ; i --) {
553- Name wcName = qname .wild (i );
554- if (nsecProvesNameError (nsec , wcName , signerName )) {
555- return true ;
556- }
577+ public static boolean nsecProvesNoWC (SRRset set , NSECRecord nsec , Name qname ) {
578+ Name ce = closestEncloser (qname , set .getName (), nsec .getNext ());
579+ int labelsToStrip = qname .labels () - ce .labels ();
580+ if (labelsToStrip > 0 ) {
581+ Name wcName = qname .wild (labelsToStrip );
582+ return nsecProvesNameError (set , nsec , wcName );
557583 }
558584
559585 return false ;
560586 }
561587
562588 /**
563589 * Container for responses of
564- * {@link ValUtils#nsecProvesNodata(NSECRecord, Name, int)}.
590+ * {@link ValUtils#nsecProvesNodata(SRRset, NSECRecord, Name, int)}.
565591 */
566592 public static class NsecProvesNodataResponse {
567593 boolean result ;
@@ -575,22 +601,23 @@ public static class NsecProvesNodataResponse {
575601 * must still be provided proof that qname did not directly exist and that
576602 * the wildcard is, in fact, *.closest_encloser.
577603 *
604+ * @param set The RRset of the NSEC record.
578605 * @param nsec The NSEC to check
579606 * @param qname The query name to check against.
580607 * @param qtype The query type to check against.
581608 * @return true if the NSEC proves the condition.
582609 */
583- public static NsecProvesNodataResponse nsecProvesNodata (NSECRecord nsec , Name qname , int qtype ) {
610+ public static NsecProvesNodataResponse nsecProvesNodata (SRRset set , NSECRecord nsec , Name qname , int qtype ) {
584611 NsecProvesNodataResponse result = new NsecProvesNodataResponse ();
585- if (!nsec .getName ().equals (qname )) {
612+ if (!set .getName ().equals (qname )) {
586613 // empty-non-terminal checking.
587614 // Done before wildcard, because this is an exact match,
588615 // and would prevent a wildcard from matching.
589616
590617 // If the nsec is proving that qname is an ENT, the nsec owner will
591618 // be less than qname, and the next name will be a child domain of
592619 // the qname.
593- if (strictSubdomain (nsec .getNext (), qname ) && nsec .getName ().compareTo (qname ) < 0 ) {
620+ if (strictSubdomain (nsec .getNext (), qname ) && set .getName ().compareTo (qname ) < 0 ) {
594621 result .result = true ;
595622 return result ;
596623 }
@@ -600,9 +627,9 @@ public static NsecProvesNodataResponse nsecProvesNodata(NSECRecord nsec, Name qn
600627 // have generated qname from the wildcard and b) the type map does
601628 // not contain qtype. Note that this does NOT prove that this
602629 // wildcard was the applicable wildcard.
603- if (nsec .getName ().isWild ()) {
630+ if (set .getName ().isWild ()) {
604631 // the is the purported closest encloser.
605- Name ce = new Name (nsec .getName (), 1 );
632+ Name ce = new Name (set .getName (), 1 );
606633
607634 // The qname must be a strict subdomain of the closest encloser,
608635 // and the qtype must be absent from the type map.
@@ -720,16 +747,16 @@ public JustifiedSecStatus nsecProvesNodataDsReply(Message request, SMessage resp
720747 }
721748
722749 NSECRecord nsec = (NSECRecord )set .first ();
723- ndp = ValUtils .nsecProvesNodata (nsec , qname , Type .DS );
750+ ndp = ValUtils .nsecProvesNodata (set , nsec , qname , Type .DS );
724751 if (ndp .result ) {
725752 hasValidNSEC = true ;
726753 if (ndp .wc != null && nsec .getName ().isWild ()) {
727754 wcNsec = nsec ;
728755 }
729756 }
730757
731- if (ValUtils .nsecProvesNameError (nsec , qname , set . getSignerName () )) {
732- ce = closestEncloser (qname , nsec );
758+ if (ValUtils .nsecProvesNameError (set , nsec , qname )) {
759+ ce = closestEncloser (qname , set . getName (), nsec . getNext () );
733760 }
734761 }
735762
0 commit comments