-
Notifications
You must be signed in to change notification settings - Fork 4
/
signedzone.go
105 lines (88 loc) · 2.56 KB
/
signedzone.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package goresolver
import (
"github.com/miekg/dns"
"log"
"strings"
"time"
)
// SignedZone represents a DNSSEC-enabled zone, its DNSKEY and DS records
type SignedZone struct {
zone string
dnskey *RRSet
ds *RRSet
parentZone *SignedZone
pubKeyLookup map[uint16]*dns.DNSKEY
}
// lookupPubkey returns a DNSKEY by its keytag
func (z SignedZone) lookupPubKey(keyTag uint16) *dns.DNSKEY {
return z.pubKeyLookup[keyTag]
}
// addPubkey stores a DNSKEY in the keytag lookup table.
func (z SignedZone) addPubKey(k *dns.DNSKEY) {
z.pubKeyLookup[k.KeyTag()] = k
}
// verifyRRSIG verifies the signature on a signed
// RRSET, and checks the validity period on the RRSIG.
// It returns nil if the RRSIG verifies and the signature
// is valid, and the appropriate error value in case
// of validation failure.
func (z SignedZone) verifyRRSIG(signedRRset *RRSet) (err error) {
if !signedRRset.IsSigned() {
return ErrInvalidRRsig
}
// Verify the RRSIG of the DNSKEY RRset
key := z.lookupPubKey(signedRRset.rrSig.KeyTag)
if key == nil {
log.Printf("DNSKEY keytag %d not found", signedRRset.rrSig.KeyTag)
return ErrDnskeyNotAvailable
}
err = signedRRset.rrSig.Verify(key, signedRRset.rrSet)
if err != nil {
log.Println("DNSKEY verification", err)
return err
}
if !signedRRset.rrSig.ValidityPeriod(time.Now()) {
log.Println("invalid validity period", err)
return ErrRrsigValidityPeriod
}
return nil
}
// verifyDS validates the DS record against the KSK
// (key signing key) of the zone.
// Return nil if the DS record matches the digest of
// the KSK.
func (z SignedZone) verifyDS(dsRrset []dns.RR) (err error) {
for _, rr := range dsRrset {
ds := rr.(*dns.DS)
if ds.DigestType != dns.SHA256 {
log.Printf("Unknown digest type (%d) on DS RR", ds.DigestType)
continue
}
parentDsDigest := strings.ToUpper(ds.Digest)
key := z.lookupPubKey(ds.KeyTag)
if key == nil {
log.Printf("DNSKEY keytag %d not found", ds.KeyTag)
return ErrDnskeyNotAvailable
}
dsDigest := strings.ToUpper(key.ToDS(ds.DigestType).Digest)
if parentDsDigest == dsDigest {
return nil
}
log.Printf("DS does not match DNSKEY\n")
return ErrDsInvalid
}
return ErrUnknownDsDigestType
}
// checkHasDnskeys returns true if the SignedZone has a DNSKEY
// record, false otherwise.
func (z *SignedZone) checkHasDnskeys() bool {
return len(z.dnskey.rrSet) > 0
}
// NewSignedZone initializes a new SignedZone and returns it.
func NewSignedZone(domainName string) *SignedZone {
return &SignedZone{
zone: domainName,
ds: &RRSet{},
dnskey: &RRSet{},
}
}