diff options
-rw-r--r-- | plugin/dnssec/dnskey.go | 21 | ||||
-rw-r--r-- | plugin/dnssec/dnssec.go | 20 | ||||
-rw-r--r-- | plugin/dnssec/dnssec_test.go | 40 | ||||
-rw-r--r-- | plugin/dnssec/responsewriter.go | 3 | ||||
-rw-r--r-- | plugin/dnssec/rrsig.go | 2 | ||||
-rw-r--r-- | plugin/dnssec/setup.go | 4 |
6 files changed, 57 insertions, 33 deletions
diff --git a/plugin/dnssec/dnskey.go b/plugin/dnssec/dnskey.go index ce787ab54..885538fbf 100644 --- a/plugin/dnssec/dnskey.go +++ b/plugin/dnssec/dnskey.go @@ -15,9 +15,10 @@ import ( // DNSKEY holds a DNSSEC public and private key used for on-the-fly signing. type DNSKEY struct { - K *dns.DNSKEY - s crypto.Signer - keytag uint16 + K *dns.DNSKEY + D *dns.DS + s crypto.Signer + tag uint16 } // ParseKeyFile read a DNSSEC keyfile as generated by dnssec-keygen or other @@ -36,18 +37,20 @@ func ParseKeyFile(pubFile, privFile string) (*DNSKEY, error) { if e != nil { return nil, e } - p, e := k.(*dns.DNSKEY).ReadPrivateKey(f, privFile) + + dk := k.(*dns.DNSKEY) + p, e := dk.ReadPrivateKey(f, privFile) if e != nil { return nil, e } - if v, ok := p.(*rsa.PrivateKey); ok { - return &DNSKEY{k.(*dns.DNSKEY), v, k.(*dns.DNSKEY).KeyTag()}, nil + if s, ok := p.(*rsa.PrivateKey); ok { + return &DNSKEY{K: dk, D: dk.ToDS(dns.SHA256), s: s, tag: dk.KeyTag()}, nil } - if v, ok := p.(*ecdsa.PrivateKey); ok { - return &DNSKEY{k.(*dns.DNSKEY), v, k.(*dns.DNSKEY).KeyTag()}, nil + if s, ok := p.(*ecdsa.PrivateKey); ok { + return &DNSKEY{K: dk, D: dk.ToDS(dns.SHA256), s: s, tag: dk.KeyTag()}, nil } - return &DNSKEY{k.(*dns.DNSKEY), nil, 0}, errors.New("no known? private key found") + return &DNSKEY{K: dk, D: dk.ToDS(dns.SHA256), s: nil, tag: 0}, errors.New("no known private key found") } // getDNSKEY returns the correct DNSKEY to the client. Signatures are added when do is true. diff --git a/plugin/dnssec/dnssec.go b/plugin/dnssec/dnssec.go index 9a20776fe..b4f738691 100644 --- a/plugin/dnssec/dnssec.go +++ b/plugin/dnssec/dnssec.go @@ -35,20 +35,30 @@ func New(zones []string, keys []*DNSKEY, next plugin.Handler, c *cache.Cache) Dn } // Sign signs the message in state. it takes care of negative or nodata responses. It -// uses NSEC black lies for authenticated denial of existence. Signatures -// creates will be cached for a short while. By default we sign for 8 days, +// uses NSEC black lies for authenticated denial of existence. For delegations it +// will insert DS records and sign those. +// Signatures will be cached for a short while. By default we sign for 8 days, // starting 3 hours ago. func (d Dnssec) Sign(state request.Request, zone string, now time.Time) *dns.Msg { req := state.Req + incep, expir := incepExpir(now) + mt, _ := response.Typify(req, time.Now().UTC()) // TODO(miek): need opt record here? if mt == response.Delegation { - // TODO(miek): uh, signing DS record?!?! + ttl := req.Ns[0].Header().Ttl + + ds := []dns.RR{} + for i := range d.keys { + ds = append(ds, d.keys[i].D) + } + if sigs, err := d.sign(ds, zone, ttl, incep, expir); err == nil { + req.Ns = append(req.Ns, ds...) + req.Ns = append(req.Ns, sigs...) + } return req } - incep, expir := incepExpir(now) - if mt == response.NameError || mt == response.NoData { if req.Ns[0].Header().Rrtype != dns.TypeSOA || len(req.Ns) > 1 { return req diff --git a/plugin/dnssec/dnssec_test.go b/plugin/dnssec/dnssec_test.go index 34c9bf331..ab41800a1 100644 --- a/plugin/dnssec/dnssec_test.go +++ b/plugin/dnssec/dnssec_test.go @@ -21,10 +21,10 @@ func TestZoneSigning(t *testing.T) { m = d.Sign(state, "miek.nl.", time.Now().UTC()) if !section(m.Answer, 1) { - t.Errorf("answer section should have 1 sig") + t.Errorf("Answer section should have 1 RRSIG") } if !section(m.Ns, 1) { - t.Errorf("authority section should have 1 sig") + t.Errorf("Authority section should have 1 RRSIG") } } @@ -40,7 +40,7 @@ func TestZoneSigningDouble(t *testing.T) { key1, err := ParseKeyFile(fPub1, fPriv1) if err != nil { - t.Fatalf("failed to parse key: %v\n", err) + t.Fatalf("Failed to parse key: %v\n", err) } d.keys = append(d.keys, key1) @@ -48,10 +48,10 @@ func TestZoneSigningDouble(t *testing.T) { state := request.Request{Req: m} m = d.Sign(state, "miek.nl.", time.Now().UTC()) if !section(m.Answer, 2) { - t.Errorf("answer section should have 1 sig") + t.Errorf("Answer section should have 1 RRSIG") } if !section(m.Ns, 2) { - t.Errorf("authority section should have 1 sig") + t.Errorf("Authority section should have 1 RRSIG") } } @@ -64,7 +64,7 @@ func TestSigningDifferentZone(t *testing.T) { key, err := ParseKeyFile(fPub, fPriv) if err != nil { - t.Fatalf("failed to parse key: %v\n", err) + t.Fatalf("Failed to parse key: %v\n", err) } m := testMsgEx() @@ -73,11 +73,11 @@ func TestSigningDifferentZone(t *testing.T) { d := New([]string{"example.org."}, []*DNSKEY{key}, nil, c) m = d.Sign(state, "example.org.", time.Now().UTC()) if !section(m.Answer, 1) { - t.Errorf("answer section should have 1 sig") + t.Errorf("Answer section should have 1 RRSIG") t.Logf("%+v\n", m) } if !section(m.Ns, 1) { - t.Errorf("authority section should have 1 sig") + t.Errorf("Authority section should have 1 RRSIG") t.Logf("%+v\n", m) } } @@ -91,7 +91,7 @@ func TestSigningCname(t *testing.T) { state := request.Request{Req: m} m = d.Sign(state, "miek.nl.", time.Now().UTC()) if !section(m.Answer, 1) { - t.Errorf("answer section should have 1 sig") + t.Errorf("Answer section should have 1 RRSIG") } } @@ -103,12 +103,24 @@ func TestZoneSigningDelegation(t *testing.T) { m := testDelegationMsg() state := request.Request{Req: m} m = d.Sign(state, "miek.nl.", time.Now().UTC()) - if !section(m.Ns, 0) { - t.Errorf("authority section should have 0 sig") + if !section(m.Ns, 1) { + t.Errorf("Authority section should have 1 RRSIG") t.Logf("%v\n", m) } + + ds := 0 + for i := range m.Ns { + if _, ok := m.Ns[i].(*dns.DS); ok { + ds++ + } + } + if ds != 1 { + t.Errorf("Authority section should have 1 DS") + t.Logf("%v\n", m) + + } if !section(m.Extra, 0) { - t.Errorf("answer section should have 0 sig") + t.Errorf("Answer section should have 0 RRSIGs") t.Logf("%v\n", m) } } @@ -123,7 +135,7 @@ func TestSigningDname(t *testing.T) { // We sign *everything* we see, also the synthesized CNAME. m = d.Sign(state, "miek.nl.", time.Now().UTC()) if !section(m.Answer, 3) { - t.Errorf("answer section should have 3 sig") + t.Errorf("Answer section should have 3 RRSIGs") } } @@ -137,7 +149,7 @@ func TestSigningEmpty(t *testing.T) { state := request.Request{Req: m} m = d.Sign(state, "miek.nl.", time.Now().UTC()) if !section(m.Ns, 2) { - t.Errorf("authority section should have 2 sig") + t.Errorf("Authority section should have 2 RRSIGs") } } diff --git a/plugin/dnssec/responsewriter.go b/plugin/dnssec/responsewriter.go index 793cbcdd0..5a38abac7 100644 --- a/plugin/dnssec/responsewriter.go +++ b/plugin/dnssec/responsewriter.go @@ -22,8 +22,7 @@ func (d *ResponseWriter) WriteMsg(res *dns.Msg) error { // which zone it should be. state := request.Request{W: d.ResponseWriter, Req: res} - qname := state.Name() - zone := plugin.Zones(d.d.zones).Matches(qname) + zone := plugin.Zones(d.d.zones).Matches(state.Name()) if zone == "" { return d.ResponseWriter.WriteMsg(res) } diff --git a/plugin/dnssec/rrsig.go b/plugin/dnssec/rrsig.go index c68413622..d67cdc926 100644 --- a/plugin/dnssec/rrsig.go +++ b/plugin/dnssec/rrsig.go @@ -8,7 +8,7 @@ func (k *DNSKEY) newRRSIG(signerName string, ttl, incep, expir uint32) *dns.RRSI sig.Hdr.Rrtype = dns.TypeRRSIG sig.Algorithm = k.K.Algorithm - sig.KeyTag = k.keytag + sig.KeyTag = k.tag sig.SignerName = signerName sig.Hdr.Ttl = ttl sig.OrigTtl = origTTL diff --git a/plugin/dnssec/setup.go b/plugin/dnssec/setup.go index 2f5c21d97..012ba5b3d 100644 --- a/plugin/dnssec/setup.go +++ b/plugin/dnssec/setup.go @@ -77,7 +77,7 @@ func dnssecParse(c *caddy.Controller) ([]string, []*DNSKEY, int, error) { zones[i] = plugin.Host(zones[i]).Normalize() } - // Check if each keys owner name can actually sign the zones we want them to sign + // Check if each keys owner name can actually sign the zones we want them to sign. for _, k := range keys { kname := plugin.Name(k.K.Header().Name) ok := false @@ -88,7 +88,7 @@ func dnssecParse(c *caddy.Controller) ([]string, []*DNSKEY, int, error) { } } if !ok { - return zones, keys, capacity, fmt.Errorf("key %s (keyid: %d) can not sign any of the zones", string(kname), k.keytag) + return zones, keys, capacity, fmt.Errorf("key %s (keyid: %d) can not sign any of the zones", string(kname), k.tag) } } |