Fold dnssec back into dns
It is more natural. Otherwise tsig and tkey needed to be put in their own packages
This commit is contained in:
parent
5ef9f57db4
commit
19edd05274
3
Makefile
3
Makefile
|
@ -12,18 +12,17 @@ GOFILES=\
|
|||
types.go\
|
||||
edns.go\
|
||||
tsig.go\
|
||||
dnssec.go\
|
||||
|
||||
|
||||
include $(GOROOT)/src/Make.pkg
|
||||
|
||||
all: package
|
||||
gomake -C dnssec package
|
||||
gomake -C resolver package
|
||||
# gomake -C strconv package
|
||||
|
||||
dnstest:
|
||||
gotest
|
||||
gomake -C dnssec test
|
||||
gomake -C resolver test
|
||||
# gomake -C strconv test
|
||||
|
||||
|
|
5
TODO
5
TODO
|
@ -9,12 +9,13 @@ Short term:
|
|||
* Signature generation
|
||||
|
||||
Issues:
|
||||
* Separation between dnssec and dns is arbitrary, why is tsig.go of package dns?
|
||||
* Better sized buffers
|
||||
* Check the network order, it works now, but this is on Intel
|
||||
* Make the testsuite work with public DNS servers
|
||||
* shortened ipv6 addresses are not parsed correctly (maby net issue)
|
||||
* shortened ipv6 addresses are not parsed correctly (maybe net issue)
|
||||
* quoted quotes in txt records
|
||||
* Convience functions?
|
||||
* Convenience functions?
|
||||
- for new(RR*)
|
||||
- nsupdate
|
||||
* query-time, server in string ouput of dns.Msg
|
||||
|
|
|
@ -0,0 +1,272 @@
|
|||
// Package dnssec implements all client side DNSSEC function, like
|
||||
// validation, keytag and DS calculation.
|
||||
package dns
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/rsa"
|
||||
"encoding/hex"
|
||||
"encoding/base64"
|
||||
"hash"
|
||||
"time"
|
||||
"io"
|
||||
"big"
|
||||
"sort"
|
||||
"strings"
|
||||
"os"
|
||||
)
|
||||
|
||||
// DNSSEC encryption algorithm codes.
|
||||
const (
|
||||
// DNSSEC algorithms
|
||||
AlgRSAMD5 = 1
|
||||
AlgDH = 2
|
||||
AlgDSA = 3
|
||||
AlgECC = 4
|
||||
AlgRSASHA1 = 5
|
||||
AlgRSASHA256 = 8
|
||||
AlgRSASHA512 = 10
|
||||
AlgECCGOST = 12
|
||||
)
|
||||
|
||||
// DNSSEC hashing codes.
|
||||
const (
|
||||
HashSHA1 = iota
|
||||
HashSHA256
|
||||
HashGOST94
|
||||
)
|
||||
|
||||
// Calculate the keytag of the DNSKEY.
|
||||
func (k *RR_DNSKEY) KeyTag() uint16 {
|
||||
var keytag int
|
||||
switch k.Algorithm {
|
||||
case AlgRSAMD5:
|
||||
println("Keytag RSAMD5. Todo")
|
||||
keytag = 0
|
||||
default:
|
||||
// Might encode header length too, so that
|
||||
// we dont need to pack/unpack all the time
|
||||
// Or a shadow structure, with the wiredata and header
|
||||
wire, ok := WireRdata(k)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
for i, v := range wire {
|
||||
if i&1 != 0 {
|
||||
keytag += int(v) // must be larger than uint32
|
||||
} else {
|
||||
keytag += int(v) << 8
|
||||
}
|
||||
}
|
||||
keytag += (keytag >> 16) & 0xFFFF
|
||||
keytag &= 0xFFFF
|
||||
}
|
||||
return uint16(keytag)
|
||||
}
|
||||
|
||||
// Convert an DNSKEY record to a DS record.
|
||||
func (k *RR_DNSKEY) ToDS(h int) *RR_DS {
|
||||
ds := new(RR_DS)
|
||||
ds.Hdr.Name = k.Hdr.Name
|
||||
ds.Hdr.Class = k.Hdr.Class
|
||||
ds.Hdr.Ttl = k.Hdr.Ttl
|
||||
ds.Algorithm = k.Algorithm
|
||||
ds.DigestType = uint8(h)
|
||||
ds.KeyTag = k.KeyTag()
|
||||
|
||||
wire, ok := WireRdata(k)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
owner, ok1 := WireDomainName(k.Hdr.Name)
|
||||
if !ok1 {
|
||||
return nil
|
||||
}
|
||||
/*
|
||||
* from RFC4034
|
||||
* digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
|
||||
* "|" denotes concatenation
|
||||
* DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
|
||||
*/
|
||||
// digest buffer
|
||||
digest := append(owner, wire...) // another copy TODO(mg)
|
||||
|
||||
switch h {
|
||||
case HashSHA1:
|
||||
s := sha1.New()
|
||||
io.WriteString(s, string(digest))
|
||||
ds.Digest = hex.EncodeToString(s.Sum())
|
||||
case HashSHA256:
|
||||
s := sha256.New()
|
||||
io.WriteString(s, string(digest))
|
||||
ds.Digest = hex.EncodeToString(s.Sum())
|
||||
case HashGOST94:
|
||||
|
||||
default:
|
||||
// wrong hash value
|
||||
return nil
|
||||
}
|
||||
return ds
|
||||
}
|
||||
|
||||
|
||||
// Validate an rrset with the signature and key. This is the
|
||||
// cryptographic test, the validity period most be check separately.
|
||||
func (s *RR_RRSIG) Verify(k *RR_DNSKEY, rrset RRset) bool {
|
||||
// Frist the easy checks
|
||||
if s.KeyTag != k.KeyTag() {
|
||||
println(s.KeyTag)
|
||||
println(k.KeyTag())
|
||||
return false
|
||||
}
|
||||
if s.Hdr.Class != k.Hdr.Class {
|
||||
println("Class")
|
||||
return false
|
||||
}
|
||||
if s.Algorithm != k.Algorithm {
|
||||
println("Class")
|
||||
return false
|
||||
}
|
||||
if s.SignerName != k.Hdr.Name {
|
||||
println(s.SignerName)
|
||||
println(k.Hdr.Name)
|
||||
return false
|
||||
}
|
||||
for _, r := range rrset {
|
||||
if r.Header().Class != s.Hdr.Class {
|
||||
return false
|
||||
}
|
||||
if r.Header().Rrtype != s.TypeCovered {
|
||||
return false
|
||||
}
|
||||
// Number of labels. TODO(mg) add helper functions
|
||||
}
|
||||
sort.Sort(rrset)
|
||||
|
||||
// RFC 4035 5.3.2. Reconstructing the Signed Data
|
||||
// Copy the sig, except the rrsig data
|
||||
s1 := &RR_RRSIG{s.Hdr, s.TypeCovered, s.Algorithm, s.Labels, s.OrigTtl, s.Expiration, s.Inception, s.KeyTag, s.SignerName, ""}
|
||||
signeddata, ok := WireRdata(s1)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, r := range rrset {
|
||||
h := r.Header()
|
||||
// RFC 4034: 6.2. Canonical RR Form. (2) - domain name to lowercase
|
||||
name := h.Name
|
||||
h.Name = strings.ToLower(h.Name)
|
||||
// 6.2. Canonical RR Form. (3) - domain rdata to lowercaser
|
||||
switch h.Rrtype {
|
||||
case TypeNS, TypeCNAME, TypeSOA, TypeMB, TypeMG, TypeMR, TypePTR:
|
||||
case TypeHINFO, TypeMINFO, TypeMX /* TypeRP, TypeAFSDB, TypeRT */ :
|
||||
case TypeSIG /* TypePX, TypeNXT /* TypeNAPTR, TypeKX */ :
|
||||
case TypeSRV, /* TypeDNAME, TypeA6 */ TypeRRSIG, TypeNSEC:
|
||||
// lower case the domain rdata //
|
||||
|
||||
}
|
||||
// 6.2. Canonical RR Form. (4) - wildcards, don't understand
|
||||
// 6.2. Canonical RR Form. (5) - origTTL
|
||||
ttl := h.Ttl
|
||||
h.Ttl = s.OrigTtl
|
||||
wire, ok1 := WireRR(r)
|
||||
h.Ttl = ttl // restore the order in the universe
|
||||
h.Name = name
|
||||
if !ok1 {
|
||||
println("Failure to pack")
|
||||
return false
|
||||
}
|
||||
signeddata = append(signeddata, wire...)
|
||||
}
|
||||
|
||||
// Buffer holding the key data
|
||||
keybuf := make([]byte, 1024)
|
||||
keybuflen := base64.StdEncoding.DecodedLen(len(k.PubKey))
|
||||
keybuflen, _ = base64.StdEncoding.Decode(keybuf[0:keybuflen], []byte(k.PubKey))
|
||||
keybuf = keybuf[:keybuflen]
|
||||
|
||||
// Buffer holding the signature
|
||||
sigbuf := make([]byte, 1024)
|
||||
sigbuflen := base64.StdEncoding.DecodedLen(len(s.Signature))
|
||||
sigbuflen, _ = base64.StdEncoding.Decode(sigbuf[0:sigbuflen], []byte(s.Signature))
|
||||
sigbuf = sigbuf[:sigbuflen]
|
||||
|
||||
var err os.Error
|
||||
switch s.Algorithm {
|
||||
case AlgRSASHA1, AlgRSASHA256, AlgRSASHA512, AlgRSAMD5:
|
||||
pubkey := rsaPubKey(keybuf)
|
||||
// Setup the hash as defined for this alg.
|
||||
var h hash.Hash
|
||||
var ch rsa.PKCS1v15Hash
|
||||
switch s.Algorithm {
|
||||
case AlgRSAMD5:
|
||||
h = md5.New()
|
||||
ch = rsa.HashMD5
|
||||
case AlgRSASHA1:
|
||||
h = sha1.New()
|
||||
ch = rsa.HashSHA1
|
||||
case AlgRSASHA256:
|
||||
h = sha256.New()
|
||||
ch = rsa.HashSHA256
|
||||
case AlgRSASHA512:
|
||||
h = sha512.New()
|
||||
ch = rsa.HashSHA512
|
||||
}
|
||||
io.WriteString(h, string(signeddata))
|
||||
sighash := h.Sum()
|
||||
err = rsa.VerifyPKCS1v15(pubkey, ch, sighash, sigbuf)
|
||||
case AlgDH:
|
||||
case AlgDSA:
|
||||
case AlgECC:
|
||||
case AlgECCGOST:
|
||||
}
|
||||
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// Using RFC1982 calculate if a signature period is valid
|
||||
func (s *RR_RRSIG) PeriodOK() bool {
|
||||
utc := time.UTC().Seconds()
|
||||
modi := (int64(s.Inception) - utc) / Year68
|
||||
mode := (int64(s.Expiration) - utc) / Year68
|
||||
ti := int64(s.Inception) + (modi * Year68)
|
||||
te := int64(s.Expiration) + (mode * Year68)
|
||||
return ti <= utc && utc <= te
|
||||
}
|
||||
|
||||
// Extra the RSA public key from the buffer
|
||||
func rsaPubKey(keybuf []byte) *rsa.PublicKey {
|
||||
// RFC 2537/3110, section 2. RSA Public KEY Resource Records
|
||||
// Length is in the 0th byte, unless its zero, then it
|
||||
// it in bytes 1 and 2 and its a 16 bit number
|
||||
explen := uint16(keybuf[0])
|
||||
keyoff := 1
|
||||
if explen == 0 {
|
||||
explen = uint16(keybuf[1])<<8 | uint16(keybuf[2])
|
||||
keyoff = 3
|
||||
}
|
||||
pubkey := new(rsa.PublicKey)
|
||||
pubkey.N = big.NewInt(0)
|
||||
shift := (explen - 1) * 8
|
||||
for i := int(explen - 1); i >= 0; i-- {
|
||||
pubkey.E += int(keybuf[keyoff+i]) << shift
|
||||
shift -= 8
|
||||
}
|
||||
pubkey.N.SetBytes(keybuf[keyoff+int(explen):])
|
||||
return pubkey
|
||||
}
|
||||
|
||||
// Map for algorithm names.
|
||||
var alg_str = map[uint8]string{
|
||||
AlgRSAMD5: "RSAMD5",
|
||||
AlgDH: "DH",
|
||||
AlgDSA: "DSA",
|
||||
AlgRSASHA1: "RSASHA1",
|
||||
AlgRSASHA256: "RSASHA256",
|
||||
AlgRSASHA512: "RSASHA512",
|
||||
AlgECCGOST: "ECC-GOST",
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package dnssec
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"fmt"
|
||||
"dns"
|
||||
)
|
||||
|
||||
func TestDnskey(t *testing.T) {
|
||||
return
|
||||
// This key was generate with LDNS:
|
||||
// ldns-keygen -a RSASHA256 -r /dev/urandom -b 1024 miek.nl
|
||||
// Show that we have al the RSA parameters and can check them
|
||||
// here to see what I came up with
|
||||
key := new(dns.RR_DNSKEY)
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Rrtype = dns.TypeDNSKEY
|
||||
key.Hdr.Class = dns.ClassINET
|
||||
key.Hdr.Ttl = 3600
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = AlgRSASHA256
|
||||
key.PubKey = "AwEAAcELcuxHosJX3LjbR6EFzsqI3mKivwvO6Y5Kzt/OXYmLQUI8tnOrX9ilT/0qGraxoONayVX3A6bl1pG3h/xOxVEGcJGqbrZnhr2+4S9tW2GWQwevV+NhinE7v6MCCCheVCnAPh0KFb/u14ng3DQizP1spBU/NoAN31l678snBpZX"
|
||||
fmt.Printf("%v\n", key)
|
||||
|
||||
soa := new(dns.RR_SOA)
|
||||
soa.Hdr = dns.RR_Header{"Miek.nl.", dns.TypeSOA, dns.ClassINET, 875, 0}
|
||||
soa.Ns = "open.nlnetlabs.nl."
|
||||
soa.Mbox = "miekg.atoom.net."
|
||||
soa.Serial = 1293513905
|
||||
soa.Refresh = 14400
|
||||
soa.Retry = 3600
|
||||
soa.Expire = 604800
|
||||
soa.Minttl = 86400
|
||||
|
||||
sig := new(dns.RR_RRSIG)
|
||||
sig.Hdr = dns.RR_Header{"miek.nl.", dns.TypeRRSIG, dns.ClassINET, 14400, 0}
|
||||
sig.TypeCovered = dns.TypeSOA
|
||||
sig.Algorithm = AlgRSASHA256
|
||||
sig.Labels = 2
|
||||
sig.Expiration = 1296098705 // date '+%s' -d"2011-01-27 04:25:05
|
||||
sig.Inception = 1293506705
|
||||
sig.OrigTtl = 14400
|
||||
//sig.KeyTag = 12051
|
||||
sig.KeyTag = 12273 //faked
|
||||
sig.SignerName = "miek.nl."
|
||||
sig.Signature = "kLq/5oFy3Sh5ZxPGFMCyHq8MtN6E17R1Ln9+bJ2Q76YYAxFE8Xlie33A1GFctH2uhzRzJKuP/JSjUkrvGk2rjBm32z9zXtZsKx/4yV0da2nLRm44NOmX6gsP4Yia8mdqPUajjkyLzAzU2bevtesJm0Z65AcmPdq3tUZODdRAcng="
|
||||
|
||||
Verify(sig, key, []dns.RR{soa})
|
||||
|
||||
// From Kmiek.nl*.private
|
||||
openssl := "135560614087352210480379313279722604826647214111257577861451621491284835543707521986085999189597017237768514876957888744370440811423088511394629855684615382349190289731989185193184712980579812986523080792122141528583964882610028199770199112837017606561901919812183422914622295620927795008308854924436086101591"
|
||||
println("OPENSSL key: what should be is: ",openssl)
|
||||
}
|
|
@ -2,8 +2,6 @@
|
|||
// validation, keytag and DS calculation.
|
||||
package dnssec
|
||||
|
||||
// Put tsig and tkey stuff here too
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
|
@ -244,7 +242,7 @@ func PeriodOK(s *dns.RR_RRSIG) bool {
|
|||
func rsaPubKey(keybuf []byte) *rsa.PublicKey {
|
||||
// RFC 2537/3110, section 2. RSA Public KEY Resource Records
|
||||
// Length is in the 0th byte, unless its zero, then it
|
||||
// it in bytes 1 and 2 and it a 16 bit number
|
||||
// it in bytes 1 and 2 and its a 16 bit number
|
||||
explen := uint16(keybuf[0])
|
||||
keyoff := 1
|
||||
if explen == 0 {
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package dnssec
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"fmt"
|
||||
"os"
|
||||
"dns"
|
||||
)
|
||||
|
||||
func TestSecure(t *testing.T) {
|
||||
// once this was valid
|
||||
soa := new(dns.RR_SOA)
|
||||
soa.Hdr = dns.RR_Header{"miek.nl.", dns.TypeSOA, dns.ClassINET, 14400, 0}
|
||||
soa.Ns = "open.nlnetlabs.nl."
|
||||
soa.Mbox = "miekg.atoom.net."
|
||||
soa.Serial = 1293945905
|
||||
soa.Refresh = 14400
|
||||
soa.Retry = 3600
|
||||
soa.Expire = 604800
|
||||
soa.Minttl = 86400
|
||||
|
||||
sig := new(dns.RR_RRSIG)
|
||||
sig.Hdr = dns.RR_Header{"miek.nl.", dns.TypeRRSIG, dns.ClassINET, 14400, 0}
|
||||
sig.TypeCovered = dns.TypeSOA
|
||||
sig.Algorithm = AlgRSASHA256
|
||||
sig.Labels = 2
|
||||
// UTC LUL!
|
||||
sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
|
||||
sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
|
||||
sig.OrigTtl = 14400
|
||||
sig.KeyTag = 12051
|
||||
sig.SignerName = "miek.nl."
|
||||
sig.Signature = "oMCbslaAVIp/8kVtLSms3tDABpcPRUgHLrOR48OOplkYo+8TeEGWwkSwaz/MRo2fB4FxW0qj/hTlIjUGuACSd+b1wKdH5GvzRJc2pFmxtCbm55ygAh4EUL0F6U5cKtGJGSXxxg6UFCQ0doJCmiGFa78LolaUOXImJrk6AFrGa0M="
|
||||
|
||||
key := new(dns.RR_DNSKEY)
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = dns.ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = AlgRSASHA256
|
||||
key.PubKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
|
||||
|
||||
fmt.Fprintf(os.Stderr, "%v\n%v\n", sig, soa)
|
||||
// It should validate. Period is checked seperately, so this will keep on working
|
||||
if ! Verify(sig, key, []dns.RR{soa}) {
|
||||
t.Log("Failure to validate")
|
||||
t.Fail()
|
||||
} else {
|
||||
println("It validates!!")
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package dnssec
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"strings"
|
||||
"dns"
|
||||
)
|
||||
|
||||
func TestKeyToDS(t *testing.T) {
|
||||
key := new(dns.RR_DNSKEY)
|
||||
key.Hdr.Name = "miek.nl"
|
||||
key.Hdr.Rrtype = dns.TypeDNSKEY
|
||||
key.Hdr.Class = dns.ClassINET
|
||||
key.Hdr.Ttl = 3600
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = AlgRSASHA256
|
||||
key.PubKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
|
||||
|
||||
ds := ToDS(key, HashSHA1)
|
||||
if strings.ToUpper(ds.Digest) != "B5121BDB5B8D86D0CC5FFAFBAAABE26C3E20BAC1" {
|
||||
t.Logf("Wrong DS digest for Sha1\n%v\n", ds)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package dnssec
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"dns"
|
||||
)
|
||||
|
||||
func TestTag(t *testing.T) {
|
||||
key := new(dns.RR_DNSKEY)
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Rrtype = dns.TypeDNSKEY
|
||||
key.Hdr.Class = dns.ClassINET
|
||||
key.Hdr.Ttl = 3600
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = AlgRSASHA256
|
||||
key.PubKey = "AwEAAcNEU67LJI5GEgF9QLNqLO1SMq1EdoQ6E9f85ha0k0ewQGCblyW2836GiVsm6k8Kr5ECIoMJ6fZWf3CQSQ9ycWfTyOHfmI3eQ/1Covhb2y4bAmL/07PhrL7ozWBW3wBfM335Ft9xjtXHPy7ztCbV9qZ4TVDTW/Iyg0PiwgoXVesz"
|
||||
|
||||
tag := KeyTag(key)
|
||||
if tag != 12051 {
|
||||
t.Logf("%v\n", key)
|
||||
t.Logf("Wrong key tag: %d\n", tag)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package dnssec
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"dns"
|
||||
)
|
||||
|
||||
func TestPackUnpack(t *testing.T) {
|
||||
out := new(dns.Msg)
|
||||
out.Answer = make([]dns.RR, 1)
|
||||
key := new(dns.RR_DNSKEY)
|
||||
key.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeDNSKEY, Class: dns.ClassINET, Ttl: 3600}
|
||||
key = &dns.RR_DNSKEY{Flags: 257, Protocol: 3, Algorithm: AlgRSASHA1}
|
||||
key.PubKey = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"
|
||||
|
||||
out.Answer[0] = key
|
||||
msg, ok := out.Pack()
|
||||
if !ok {
|
||||
t.Log("Failed to pack msg with DNSKEY")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
in := new(dns.Msg)
|
||||
if !in.Unpack(msg) {
|
||||
t.Log("Failed to unpack msg with DNSKEY")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
sig := new(dns.RR_RRSIG)
|
||||
sig.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeRRSIG, Class: dns.ClassINET, Ttl: 3600}
|
||||
sig = &dns.RR_RRSIG{TypeCovered: dns.TypeDNSKEY, Algorithm: AlgRSASHA1, Labels: 2,
|
||||
OrigTtl: 3600, Expiration: 4000, Inception: 4000, KeyTag: 34641, SignerName: "miek.nl.",
|
||||
Signature: "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"}
|
||||
|
||||
out.Answer[0] = sig
|
||||
msg, ok = out.Pack()
|
||||
if !ok {
|
||||
t.Log("Failed to pack msg with RRSIG")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if !in.Unpack(msg) {
|
||||
t.Log("Failed to unpack msg with RRSIG")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package dnssec
|
||||
|
||||
import (
|
||||
"dns"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSignature(t *testing.T) {
|
||||
sig := new(dns.RR_RRSIG)
|
||||
sig.Hdr.Name = "miek.nl."
|
||||
sig.Hdr.Class = dns.ClassINET
|
||||
sig.Hdr.Ttl = 3600
|
||||
sig.TypeCovered = dns.TypeDNSKEY
|
||||
sig.Algorithm = AlgRSASHA1
|
||||
sig.Labels = 2
|
||||
sig.OrigTtl = 4000
|
||||
sig.Expiration = 1000 //Thu Jan 1 02:06:40 CET 1970
|
||||
sig.Inception = 800 //Thu Jan 1 01:13:20 CET 1970
|
||||
sig.KeyTag = 34641
|
||||
sig.SignerName = "miek.nl."
|
||||
sig.Signature = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"
|
||||
|
||||
// Should not be valid
|
||||
if PeriodOK(sig) {
|
||||
t.Log("Should not be valid")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
sig.Inception = 315565800 //Tue Jan 1 10:10:00 CET 1980
|
||||
sig.Expiration = 4102477800 //Fri Jan 1 10:10:00 CET 2100
|
||||
if ! PeriodOK(sig) {
|
||||
t.Log("Should be valid")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
38
pack_test.go
38
pack_test.go
|
@ -2,48 +2,44 @@ package dns
|
|||
|
||||
import (
|
||||
"testing"
|
||||
"net"
|
||||
)
|
||||
|
||||
func TestPackUnpack(t *testing.T) {
|
||||
out := new(Msg)
|
||||
r := new(RR_AAAA)
|
||||
r.AAAA = net.ParseIP("2001:7b8:206:1:200:39ff:fe59:b187").To16()
|
||||
r.Hdr = RR_Header{Name: "a.miek.nl", Rrtype: TypeAAAA, Class: ClassINET, Ttl: 3600}
|
||||
out.Answer = make([]RR, 1)
|
||||
out.Answer[0] = r
|
||||
key := new(RR_DNSKEY)
|
||||
key.Hdr = RR_Header{Name: "miek.nl.", Rrtype: TypeDNSKEY, Class: ClassINET, Ttl: 3600}
|
||||
key = &RR_DNSKEY{Flags: 257, Protocol: 3, Algorithm: AlgRSASHA1}
|
||||
key.PubKey = "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"
|
||||
|
||||
out.Answer[0] = key
|
||||
msg, ok := out.Pack()
|
||||
if !ok {
|
||||
t.Log("Failed to pack msg with AAAA")
|
||||
t.Log("Failed to pack msg with DNSKEY")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
in := new(Msg)
|
||||
if !in.Unpack(msg) {
|
||||
t.Log("Failed to unpack msg with AAAA")
|
||||
t.Log("Failed to unpack msg with DNSKEY")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
edns := new(RR_OPT)
|
||||
edns.Hdr.Name = "."
|
||||
edns.Hdr.Rrtype = TypeOPT
|
||||
edns.Hdr.Class = ClassINET
|
||||
edns.Hdr.Ttl = 3600
|
||||
edns.Option = make([]Option, 1)
|
||||
edns.SetNsidToString("lalalala")
|
||||
sig := new(RR_RRSIG)
|
||||
sig.Hdr = RR_Header{Name: "miek.nl.", Rrtype: TypeRRSIG, Class: ClassINET, Ttl: 3600}
|
||||
sig = &RR_RRSIG{TypeCovered: TypeDNSKEY, Algorithm: AlgRSASHA1, Labels: 2,
|
||||
OrigTtl: 3600, Expiration: 4000, Inception: 4000, KeyTag: 34641, SignerName: "miek.nl.",
|
||||
Signature: "AwEAAaHIwpx3w4VHKi6i1LHnTaWeHCL154Jug0Rtc9ji5qwPXpBo6A5sRv7cSsPQKPIwxLpyCrbJ4mr2L0EPOdvP6z6YfljK2ZmTbogU9aSU2fiq/4wjxbdkLyoDVgtO+JsxNN4bjr4WcWhsmk1Hg93FV9ZpkWb0Tbad8DFqNDzr//kZ"}
|
||||
|
||||
_, ok = packRR(edns, msg, 0)
|
||||
out.Answer[0] = sig
|
||||
msg, ok = out.Pack()
|
||||
if !ok {
|
||||
t.Logf("%v\n", edns)
|
||||
t.Log("Failed")
|
||||
t.Log("Failed to pack msg with RRSIG")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
unpacked, _, ok := unpackRR(msg, 0)
|
||||
if !ok {
|
||||
t.Logf("%v\n", unpacked)
|
||||
t.Log("Failed")
|
||||
if !in.Unpack(msg) {
|
||||
t.Log("Failed to unpack msg with RRSIG")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func TestResolver(t *testing.T) {
|
|||
ch <- DnsMsg{m, nil}
|
||||
in := <-ch
|
||||
|
||||
if in.Dns.Rcode != dns.RcodeSuccess {
|
||||
if in.Dns != nil && in.Dns.Rcode != dns.RcodeSuccess {
|
||||
t.Log("Failed to get an valid answer")
|
||||
t.Fail()
|
||||
t.Logf("%v\n", in)
|
||||
|
@ -33,7 +33,7 @@ func TestResolver(t *testing.T) {
|
|||
ch <- DnsMsg{m, nil}
|
||||
in = <-ch
|
||||
|
||||
if in.Dns.Rcode != dns.RcodeSuccess {
|
||||
if in.Dns != nil && in.Dns.Rcode != dns.RcodeSuccess {
|
||||
t.Log("Failed to get an valid answer")
|
||||
t.Fail()
|
||||
t.Logf("%v\n", in)
|
||||
|
|
70
tsig.go
70
tsig.go
|
@ -1,7 +1,11 @@
|
|||
package dns
|
||||
|
||||
// Implementation of TSIG
|
||||
// Generation an Validation
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"strconv"
|
||||
"io"
|
||||
)
|
||||
|
||||
|
@ -11,6 +15,35 @@ const (
|
|||
HmacSHA1
|
||||
)
|
||||
|
||||
type RR_TSIG struct {
|
||||
Hdr RR_Header
|
||||
Algorithm string "domain-name"
|
||||
TimeSigned [3]uint16 "TSIG"
|
||||
Fudge uint16
|
||||
MACSize uint16
|
||||
MAC string
|
||||
OrigId uint16 // msg id
|
||||
Error uint16
|
||||
OtherLen uint16
|
||||
OtherData string
|
||||
}
|
||||
|
||||
func (rr *RR_TSIG) Header() *RR_Header {
|
||||
return &rr.Hdr
|
||||
}
|
||||
|
||||
func (rr *RR_TSIG) String() string {
|
||||
// It has no presentation format
|
||||
return rr.Hdr.String() +
|
||||
" " + rr.Algorithm +
|
||||
" " + "<timesigned>" +
|
||||
" " + strconv.Itoa(int(rr.Fudge)) +
|
||||
" " + "<MAC>" +
|
||||
" " + strconv.Itoa(int(rr.OrigId)) +
|
||||
" " + strconv.Itoa(int(rr.Error)) +
|
||||
" " + rr.OtherData
|
||||
}
|
||||
|
||||
// The following values must be put in wireformat, so that
|
||||
// the MAC can be calculated
|
||||
// RFC 2845, section 3.4.2. TSIG Variables
|
||||
|
@ -32,21 +65,25 @@ type tsig_generation_fmt struct {
|
|||
// Generate the HMAC for msg. The TSIG RR is modified
|
||||
// to include the MAC and MACSize. Note the the msg Id must
|
||||
// be set, otherwise the MAC is not correct
|
||||
func (rr *RR_TSIG) GenerateMAC(msg *Msg, secret string) bool {
|
||||
func (rr *RR_TSIG) Generate(msg *Msg, secret string) bool {
|
||||
buf := make([]byte, 4096) // TODO(mg) bufsize!
|
||||
tsigbuf := new(tsig_generation_fmt)
|
||||
tsig := new(tsig_generation_fmt)
|
||||
|
||||
// Fill the struct and generate the wiredata
|
||||
tsigbuf.Name = rr.Header().Name
|
||||
tsigbuf.Class = rr.Header().Class
|
||||
tsigbuf.Ttl = rr.Header().Ttl
|
||||
tsigbuf.Algorithm = rr.Algorithm
|
||||
tsigbuf.TimeSigned = rr.TimeSigned
|
||||
tsigbuf.Fudge = rr.Fudge
|
||||
tsigbuf.Error = rr.Error
|
||||
tsigbuf.OtherLen = rr.OtherLen
|
||||
tsigbuf.OtherData = rr.OtherData
|
||||
packStruct(tsigbuf, buf, 0)
|
||||
tsig.Name = rr.Header().Name
|
||||
tsig.Class = rr.Header().Class
|
||||
tsig.Ttl = rr.Header().Ttl
|
||||
tsig.Algorithm = rr.Algorithm
|
||||
tsig.TimeSigned = rr.TimeSigned
|
||||
tsig.Fudge = rr.Fudge
|
||||
tsig.Error = rr.Error
|
||||
tsig.OtherLen = rr.OtherLen
|
||||
tsig.OtherData = rr.OtherData
|
||||
n, ok1 := packStruct(tsig, buf, 0)
|
||||
if !ok1 {
|
||||
return false
|
||||
}
|
||||
buf = buf[:n]
|
||||
|
||||
msgbuf, ok := msg.Pack()
|
||||
if !ok {
|
||||
|
@ -54,12 +91,17 @@ func (rr *RR_TSIG) GenerateMAC(msg *Msg, secret string) bool {
|
|||
}
|
||||
buf = append(buf, msgbuf...)
|
||||
|
||||
//func NewMD5(key []byte) hash.Hash
|
||||
hmac := hmac.NewMD5([]byte(secret))
|
||||
io.WriteString(hmac, string(buf))
|
||||
rr.MAC = string(hmac.Sum())
|
||||
rr.MACSize = uint16(len(rr.MAC))
|
||||
rr.OrigId = msg.MsgHdr.Id
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Verify a TSIG. The msg should be the complete message with
|
||||
// the TSIG record still attached (as the last rr in the Additional
|
||||
// section)
|
||||
func (rr *RR_TSIG) Verify(msg *Msg, secret string) bool {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
func TestTsig(t *testing.T) {
|
||||
tsig := new(RR_TSIG)
|
||||
tsig.Hdr.Name = "miek.nl" // for tsig this is the key's name
|
||||
tsig.Hdr.Name = "miek.nl." // for tsig this is the key's name
|
||||
tsig.Hdr.Rrtype = TypeTSIG
|
||||
tsig.Hdr.Class = ClassANY
|
||||
tsig.Hdr.Ttl = 0
|
||||
|
@ -15,9 +15,9 @@ func TestTsig(t *testing.T) {
|
|||
out := new(Msg)
|
||||
out.MsgHdr.RecursionDesired = true
|
||||
out.Question = make([]Question, 1)
|
||||
out.Question[0] = Question{"miek.nl", TypeSOA, ClassINET}
|
||||
out.Question[0] = Question{"miek.nl.", TypeSOA, ClassINET}
|
||||
|
||||
ok := tsig.GenerateMAC(out, "geheim")
|
||||
ok := tsig.Generate(out, "geheim")
|
||||
if !ok {
|
||||
t.Log("Failed")
|
||||
t.Fail()
|
||||
|
|
24
types.go
24
types.go
|
@ -524,30 +524,6 @@ func (rr *RR_TKEY) String() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
type RR_TSIG struct {
|
||||
Hdr RR_Header
|
||||
Algorithm string "domain-name"
|
||||
TimeSigned [3]uint16 "TSIG"
|
||||
Fudge uint16
|
||||
MACSize uint16
|
||||
MAC string
|
||||
OrigId uint16 // msg id
|
||||
Error uint16
|
||||
OtherLen uint16
|
||||
OtherData string
|
||||
}
|
||||
|
||||
func (rr *RR_TSIG) Header() *RR_Header {
|
||||
return &rr.Hdr
|
||||
}
|
||||
|
||||
func (rr *RR_TSIG) String() string {
|
||||
// It has no presentation format
|
||||
return rr.Hdr.String() +
|
||||
" " + strconv.Itoa(int(rr.MACSize)) +
|
||||
" " + rr.MAC
|
||||
}
|
||||
|
||||
// Translate the RRSIG's incep. and expir. time to the correct date.
|
||||
// Taking into account serial arithmetic (RFC 1982)
|
||||
func timeToDate(t uint32) string {
|
||||
|
|
Loading…
Reference in New Issue