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:
Miek Gieben 2011-01-09 10:31:23 +01:00
parent 5ef9f57db4
commit 19edd05274
15 changed files with 364 additions and 317 deletions

View File

@ -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
View File

@ -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

272
dnssec.go Normal file
View File

@ -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",
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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!!")
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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
out.Answer = make([]RR, 1)
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)
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()
}
}

View File

@ -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)

84
tsig.go
View File

@ -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,34 +65,43 @@ 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 {
return false
}
buf = append(buf, msgbuf...)
msgbuf, ok := msg.Pack()
if !ok {
return false
}
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
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
}

View File

@ -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()

View File

@ -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 {