coredns-rfc2136/config.go

79 lines
2.7 KiB
Go
Raw Normal View History

package rfc2136
import (
"encoding/base64"
"fmt"
"strings"
"github.com/miekg/dns"
)
// tsigKey is a single pre-shared TSIG credential. The plugin holds one
// per declared `tsig-key` directive, keyed in RFC2136.TSIGKeys by the
// canonical (lowercased, trailing-dot) key name.
//
// Phase 1.2 stores the algorithm and decoded secret. Phase 1.4 will
// use them for actual signature verification via dns.TsigSecret +
// dns.Msg.IsTsig() / dns.TsigVerify().
type tsigKey struct {
// Algorithm is the canonical miekg/dns algorithm identifier, e.g.
// dns.HmacSHA256 ("hmac-sha256."). Stored in dns-library form so
// it's directly usable when wiring TSIG verification later.
Algorithm string
// Secret is the base64-decoded raw bytes of the shared secret.
// Decoding at parse time means a malformed secret fails Corefile
// load (loud), not mid-query (silent).
Secret []byte
}
// supportedTSIGAlgorithms maps user-facing algorithm names (as written
// in Corefile) to the canonical names recognised by miekg/dns. Only
// SHA-family entries are included — HMAC-MD5 is deprecated and not
// supported here on principle.
var supportedTSIGAlgorithms = map[string]string{
"hmac-sha1": dns.HmacSHA1,
"hmac-sha224": dns.HmacSHA224,
"hmac-sha256": dns.HmacSHA256,
"hmac-sha384": dns.HmacSHA384,
"hmac-sha512": dns.HmacSHA512,
}
// parseTSIGAlgorithm validates and canonicalises the algorithm name
// from a `tsig-key` directive. Returns the miekg/dns canonical form
// (which has a trailing dot per DNS-name convention).
func parseTSIGAlgorithm(s string) (string, error) {
canon, ok := supportedTSIGAlgorithms[strings.ToLower(s)]
if !ok {
return "", fmt.Errorf("unsupported TSIG algorithm %q (supported: hmac-sha1, hmac-sha224, hmac-sha256, hmac-sha384, hmac-sha512)", s)
}
return canon, nil
}
// decodeTSIGSecret validates the base64-encoded TSIG secret from the
// Corefile and returns the raw bytes. Rejects empty secrets and any
// secret shorter than 8 bytes (well under the HMAC algorithm's block
// size for any supported algorithm — anything that short is almost
// certainly a typo, not deliberate).
func decodeTSIGSecret(s string) ([]byte, error) {
raw, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, fmt.Errorf("invalid base64 in TSIG secret: %w", err)
}
if len(raw) < 8 {
return nil, fmt.Errorf("TSIG secret too short (%d bytes after base64-decode; need >= 8)", len(raw))
}
return raw, nil
}
// canonicalKeyName normalises a TSIG key name to lowercase + trailing
// dot. miekg/dns expects the dot-terminated FQDN form internally, so
// we coerce here once at parse-time rather than every lookup.
func canonicalKeyName(name string) string {
name = strings.ToLower(name)
if !strings.HasSuffix(name, ".") {
name += "."
}
return name
}