Hi,

Some time ago I started a thread in a DNSSEC mailing list asking about
signing a zone in two different locations, and which considerations I
should take[1]. My intention was to create identical signed zone in
different locations.

Currently OpenDNSSEC can't do that because the inception date depends on
the time the data is being signed, and the expiration date depends on a
random jitter. So, to ensure the signatures have equal
inception/expiration, you need to remove the time/randomness dependencies.

I've worked in the following solution using version 1.1.0

- inception doesn't depend on the current time, but in the current hour.
That criteria can be changed to round the time to certain unit of time.

- expiration still uses a jitter, but is not a uniformly distributed
random variable, but a step function that takes as input the RRset label
and returns a value between [0, 2*JITTER]. By using this, you make the
jitter to depend on the label. Initially I tested using the relative
number of the RRset within the zone, but if you provide zones with equal
content but different order, the signatures won't be the same.

Recently I updated to 1.1.2 and previous patch were not usable directly,
so I rewrote and tested.

Using two boxes running the same patched version of OpenDNSSEC, with the
same KASP, keys and state (files in /var/opendnssec/tmp), from the same
input zone we generated the same signed zone in both boxes. The signing
process started with a two-minute difference and even one of the signing
boxes took double the time to finish the signing.

The distribution of the signature expiration date is still good, but not
perfect. That depends on the quality of the hash function used to
calculate the jitter. I'm attaching a graph with expiration distribution
of my test zone.

CAVEATS:
- the signing process has to start in the same hour.
- the current jitter generation behavior is hard-coded, including the
unit of time used to round down the inception time. It seems reasonable,
if the feature is approved, to make changes to the kasp.xml to signal
which mechanism use to generate jitter.

TODO
- Test with more and bigger zones. My test zone has 50,000 records.


I hoping to generate some discussion about the correctness of the
solution. The corresponding patches are attached.

cheers,

[1]
http://dnssec-deployment.org/pipermail/dnssec-deployment/2010-February/003653.html
-- 
Sebastian Castro
DNS Specialist
.nz Registry Services (New Zealand Domain Name Registry Limited)
desk: +64 4 495 2337
mobile: +64 21 400535
Index: signer/src/signer/rrset.c
===================================================================
--- signer/src/signer/rrset.c	(revision 3778)
+++ signer/src/signer/rrset.c	(working copy)
@@ -433,7 +433,7 @@
  */
 static void
 rrset_sign_set_timers(signconf_type* sc, ldns_rr_type rrtype, time_t signtime,
-    time_t* inception, time_t* expiration)
+    double mult, time_t* inception, time_t* expiration)
 {
     time_t jitter = 0;
     time_t offset = 0;
@@ -447,6 +447,7 @@
     jitter = duration2time(sc->sig_jitter);
     if (jitter) {
         random_jitter = se_rand(jitter*2);
+        random_jitter = (time_t)2 * mult * jitter;
     }
     offset = duration2time(sc->sig_inception_offset);
     if (rrtype == LDNS_RR_TYPE_NSEC || rrtype == LDNS_RR_TYPE_NSEC3) {
@@ -523,6 +524,7 @@
     key_type* key = NULL;
     time_t inception = 0;
     time_t expiration = 0;
+    double jitter_mul = 0.0; 
 
     se_log_assert(rrset);
     se_log_assert(sc);
@@ -541,8 +543,11 @@
                     "list", rrset->rr_type);
                 return 1;
             }
+            /* XXX Find the owner name for the rr_list */
+            /* XXX Calculate an index based on the owner name */
+            jitter_mul = get_jitter_step(rrset_get_label(rrset));
             rrset_sign_set_timers(sc, rrset->rr_type, signtime,
-                 &inception, &expiration);
+                 jitter_mul, &inception, &expiration);
             key = sc->keys->first_key;
             while (key) {
                 if ((!key->zsk && rrset->rr_type != LDNS_RR_TYPE_DNSKEY) ||
@@ -693,3 +698,46 @@
     }
     return;
 }
+
+/**
+ * Find the label for a RRset
+ */
+char *
+rrset_get_label(rrset_type* rrset)
+{
+    ldns_dnssec_rrs* rrs = NULL;
+
+    rrs = rrset->rrs;
+    while (rrs) {
+        if (rrs->rr) {
+            return ldns_rdf2str(rrs->rr->_owner);
+        }
+        rrs = rrs->next;
+    }
+
+    return NULL;
+}
+
+unsigned long
+str2hash(char *str)
+{
+    unsigned long hash = 5381;
+    int c;
+
+    while( (c = *str++) )
+        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+    return hash;
+}
+
+
+double
+get_jitter_step(char *str) {
+    /* First get the hash for the given string */
+    unsigned long hash = str2hash(str);
+    /* Normalize the value to something between [0, 1] */
+    double step = (double)(hash % 503) / 503;
+
+    return step;
+}
+
Index: signer/src/signer/rrset.h
===================================================================
--- signer/src/signer/rrset.h	(revision 3778)
+++ signer/src/signer/rrset.h	(working copy)
@@ -153,4 +153,7 @@
  */
 void rrset_print_rrsig(FILE* fd, rrset_type* rrset);
 
+char* rrset_get_label(rrset_type* rrset);
+
+double get_jitter_step(char* str);
 #endif /* SIGNER_RRSET_H */
Index: signer/src/signer/zonedata.c
===================================================================
--- signer/src/signer/zonedata.c	(revision 3778)
+++ signer/src/signer/zonedata.c	(working copy)
@@ -772,7 +772,7 @@
         return 1;
     }
 
-    now = time_now();
+    now = time_cur_hour();
     ctx = hsm_create_context();
     if (!ctx) {
         se_log_error("error creating libhsm context");
Index: signer/src/util/duration.c
===================================================================
--- signer/src/util/duration.c	(revision 3778)
+++ signer/src/util/duration.c	(working copy)
@@ -419,7 +419,27 @@
     return time(NULL);
 }
 
+/**
+ * Return the time since Epoch in seconds, rounded to the hour
+ *
+ */
+time_t
+time_cur_hour(void)
+{
+    time_t tmp_t = 0;
+#ifdef ENFORCER_TIMESHIFT
+    const char* env = getenv("ENFORCER_TIMESHIFT");
+    if (env) {
+        tmp_t timeshift2time(env);
+    } else
+#endif /* ENFORCER_TIMESHIFT */
 
+    tmp_t = time(NULL);
+
+    return HOUR_T*(tmp_t/HOUR_T);
+}
+
+
 /**
  * copycode: This code is based on the EXAMPLE in the strftime manual.
  *
Index: signer/src/util/duration.h
===================================================================
--- signer/src/util/duration.h	(revision 3778)
+++ signer/src/util/duration.h	(working copy)
@@ -39,6 +39,9 @@
 #include <stdint.h>
 #include <time.h>
 
+/* Number of seconds in an hour, used by time_cur_hour to round down */
+#define HOUR_T 3600
+
 /**
  * Duration.
  *
@@ -144,6 +147,7 @@
  *
  */
 time_t time_now(void);
+time_t time_cur_hour(void);
 
 /**
  * Clean up duration.

<<inline: signature-expiration.png>>

_______________________________________________
Opendnssec-user mailing list
[email protected]
https://lists.opendnssec.org/mailman/listinfo/opendnssec-user

Reply via email to