1package dns
2
3import (
4	"bytes"
5	"crypto"
6	"crypto/dsa"
7	"crypto/ecdsa"
8	"crypto/elliptic"
9	_ "crypto/md5"
10	"crypto/rand"
11	"crypto/rsa"
12	_ "crypto/sha1"
13	_ "crypto/sha256"
14	_ "crypto/sha512"
15	"encoding/asn1"
16	"encoding/binary"
17	"encoding/hex"
18	"math/big"
19	"sort"
20	"strings"
21	"time"
22)
23
24// DNSSEC encryption algorithm codes.
25const (
26	_ uint8 = iota
27	RSAMD5
28	DH
29	DSA
30	_ // Skip 4, RFC 6725, section 2.1
31	RSASHA1
32	DSANSEC3SHA1
33	RSASHA1NSEC3SHA1
34	RSASHA256
35	_ // Skip 9, RFC 6725, section 2.1
36	RSASHA512
37	_ // Skip 11, RFC 6725, section 2.1
38	ECCGOST
39	ECDSAP256SHA256
40	ECDSAP384SHA384
41	INDIRECT   uint8 = 252
42	PRIVATEDNS uint8 = 253 // Private (experimental keys)
43	PRIVATEOID uint8 = 254
44)
45
46// Map for algorithm names.
47var AlgorithmToString = map[uint8]string{
48	RSAMD5:           "RSAMD5",
49	DH:               "DH",
50	DSA:              "DSA",
51	RSASHA1:          "RSASHA1",
52	DSANSEC3SHA1:     "DSA-NSEC3-SHA1",
53	RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
54	RSASHA256:        "RSASHA256",
55	RSASHA512:        "RSASHA512",
56	ECCGOST:          "ECC-GOST",
57	ECDSAP256SHA256:  "ECDSAP256SHA256",
58	ECDSAP384SHA384:  "ECDSAP384SHA384",
59	INDIRECT:         "INDIRECT",
60	PRIVATEDNS:       "PRIVATEDNS",
61	PRIVATEOID:       "PRIVATEOID",
62}
63
64// Map of algorithm strings.
65var StringToAlgorithm = reverseInt8(AlgorithmToString)
66
67// Map of algorithm crypto hashes.
68var AlgorithmToHash = map[uint8]crypto.Hash{
69	RSAMD5:           crypto.MD5, // Deprecated in RFC 6725
70	RSASHA1:          crypto.SHA1,
71	RSASHA1NSEC3SHA1: crypto.SHA1,
72	RSASHA256:        crypto.SHA256,
73	ECDSAP256SHA256:  crypto.SHA256,
74	ECDSAP384SHA384:  crypto.SHA384,
75	RSASHA512:        crypto.SHA512,
76}
77
78// DNSSEC hashing algorithm codes.
79const (
80	_      uint8 = iota
81	SHA1         // RFC 4034
82	SHA256       // RFC 4509
83	GOST94       // RFC 5933
84	SHA384       // Experimental
85	SHA512       // Experimental
86)
87
88// Map for hash names.
89var HashToString = map[uint8]string{
90	SHA1:   "SHA1",
91	SHA256: "SHA256",
92	GOST94: "GOST94",
93	SHA384: "SHA384",
94	SHA512: "SHA512",
95}
96
97// Map of hash strings.
98var StringToHash = reverseInt8(HashToString)
99
100// DNSKEY flag values.
101const (
102	SEP    = 1
103	REVOKE = 1 << 7
104	ZONE   = 1 << 8
105)
106
107// The RRSIG needs to be converted to wireformat with some of the rdata (the signature) missing.
108type rrsigWireFmt struct {
109	TypeCovered uint16
110	Algorithm   uint8
111	Labels      uint8
112	OrigTtl     uint32
113	Expiration  uint32
114	Inception   uint32
115	KeyTag      uint16
116	SignerName  string `dns:"domain-name"`
117	/* No Signature */
118}
119
120// Used for converting DNSKEY's rdata to wirefmt.
121type dnskeyWireFmt struct {
122	Flags     uint16
123	Protocol  uint8
124	Algorithm uint8
125	PublicKey string `dns:"base64"`
126	/* Nothing is left out */
127}
128
129func divRoundUp(a, b int) int {
130	return (a + b - 1) / b
131}
132
133// KeyTag calculates the keytag (or key-id) of the DNSKEY.
134func (k *DNSKEY) KeyTag() uint16 {
135	if k == nil {
136		return 0
137	}
138	var keytag int
139	switch k.Algorithm {
140	case RSAMD5:
141		// Look at the bottom two bytes of the modules, which the last
142		// item in the pubkey. We could do this faster by looking directly
143		// at the base64 values. But I'm lazy.
144		modulus, _ := fromBase64([]byte(k.PublicKey))
145		if len(modulus) > 1 {
146			x := binary.BigEndian.Uint16(modulus[len(modulus)-2:])
147			keytag = int(x)
148		}
149	default:
150		keywire := new(dnskeyWireFmt)
151		keywire.Flags = k.Flags
152		keywire.Protocol = k.Protocol
153		keywire.Algorithm = k.Algorithm
154		keywire.PublicKey = k.PublicKey
155		wire := make([]byte, DefaultMsgSize)
156		n, err := packKeyWire(keywire, wire)
157		if err != nil {
158			return 0
159		}
160		wire = wire[:n]
161		for i, v := range wire {
162			if i&1 != 0 {
163				keytag += int(v) // must be larger than uint32
164			} else {
165				keytag += int(v) << 8
166			}
167		}
168		keytag += (keytag >> 16) & 0xFFFF
169		keytag &= 0xFFFF
170	}
171	return uint16(keytag)
172}
173
174// ToDS converts a DNSKEY record to a DS record.
175func (k *DNSKEY) ToDS(h uint8) *DS {
176	if k == nil {
177		return nil
178	}
179	ds := new(DS)
180	ds.Hdr.Name = k.Hdr.Name
181	ds.Hdr.Class = k.Hdr.Class
182	ds.Hdr.Rrtype = TypeDS
183	ds.Hdr.Ttl = k.Hdr.Ttl
184	ds.Algorithm = k.Algorithm
185	ds.DigestType = h
186	ds.KeyTag = k.KeyTag()
187
188	keywire := new(dnskeyWireFmt)
189	keywire.Flags = k.Flags
190	keywire.Protocol = k.Protocol
191	keywire.Algorithm = k.Algorithm
192	keywire.PublicKey = k.PublicKey
193	wire := make([]byte, DefaultMsgSize)
194	n, err := packKeyWire(keywire, wire)
195	if err != nil {
196		return nil
197	}
198	wire = wire[:n]
199
200	owner := make([]byte, 255)
201	off, err1 := PackDomainName(strings.ToLower(k.Hdr.Name), owner, 0, nil, false)
202	if err1 != nil {
203		return nil
204	}
205	owner = owner[:off]
206	// RFC4034:
207	// digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
208	// "|" denotes concatenation
209	// DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
210
211	// digest buffer
212	digest := append(owner, wire...) // another copy
213
214	var hash crypto.Hash
215	switch h {
216	case SHA1:
217		hash = crypto.SHA1
218	case SHA256:
219		hash = crypto.SHA256
220	case SHA384:
221		hash = crypto.SHA384
222	case SHA512:
223		hash = crypto.SHA512
224	default:
225		return nil
226	}
227
228	s := hash.New()
229	s.Write(digest)
230	ds.Digest = hex.EncodeToString(s.Sum(nil))
231	return ds
232}
233
234// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
235func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
236	c := &CDNSKEY{DNSKEY: *k}
237	c.Hdr = *k.Hdr.copyHeader()
238	c.Hdr.Rrtype = TypeCDNSKEY
239	return c
240}
241
242// ToCDS converts a DS record to a CDS record.
243func (d *DS) ToCDS() *CDS {
244	c := &CDS{DS: *d}
245	c.Hdr = *d.Hdr.copyHeader()
246	c.Hdr.Rrtype = TypeCDS
247	return c
248}
249
250// Sign signs an RRSet. The signature needs to be filled in with the values:
251// Inception, Expiration, KeyTag, SignerName and Algorithm.  The rest is copied
252// from the RRset. Sign returns a non-nill error when the signing went OK.
253// There is no check if RRSet is a proper (RFC 2181) RRSet.  If OrigTTL is non
254// zero, it is used as-is, otherwise the TTL of the RRset is used as the
255// OrigTTL.
256func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
257	if k == nil {
258		return ErrPrivKey
259	}
260	// s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set
261	if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
262		return ErrKey
263	}
264
265	rr.Hdr.Rrtype = TypeRRSIG
266	rr.Hdr.Name = rrset[0].Header().Name
267	rr.Hdr.Class = rrset[0].Header().Class
268	if rr.OrigTtl == 0 { // If set don't override
269		rr.OrigTtl = rrset[0].Header().Ttl
270	}
271	rr.TypeCovered = rrset[0].Header().Rrtype
272	rr.Labels = uint8(CountLabel(rrset[0].Header().Name))
273
274	if strings.HasPrefix(rrset[0].Header().Name, "*") {
275		rr.Labels-- // wildcard, remove from label count
276	}
277
278	sigwire := new(rrsigWireFmt)
279	sigwire.TypeCovered = rr.TypeCovered
280	sigwire.Algorithm = rr.Algorithm
281	sigwire.Labels = rr.Labels
282	sigwire.OrigTtl = rr.OrigTtl
283	sigwire.Expiration = rr.Expiration
284	sigwire.Inception = rr.Inception
285	sigwire.KeyTag = rr.KeyTag
286	// For signing, lowercase this name
287	sigwire.SignerName = strings.ToLower(rr.SignerName)
288
289	// Create the desired binary blob
290	signdata := make([]byte, DefaultMsgSize)
291	n, err := packSigWire(sigwire, signdata)
292	if err != nil {
293		return err
294	}
295	signdata = signdata[:n]
296	wire, err := rawSignatureData(rrset, rr)
297	if err != nil {
298		return err
299	}
300	signdata = append(signdata, wire...)
301
302	hash, ok := AlgorithmToHash[rr.Algorithm]
303	if !ok {
304		return ErrAlg
305	}
306
307	h := hash.New()
308	h.Write(signdata)
309
310	signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
311	if err != nil {
312		return err
313	}
314
315	rr.Signature = toBase64(signature)
316
317	return nil
318}
319
320func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) {
321	signature, err := k.Sign(rand.Reader, hashed, hash)
322	if err != nil {
323		return nil, err
324	}
325
326	switch alg {
327	case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
328		return signature, nil
329
330	case ECDSAP256SHA256, ECDSAP384SHA384:
331		ecdsaSignature := &struct {
332			R, S *big.Int
333		}{}
334		if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil {
335			return nil, err
336		}
337
338		var intlen int
339		switch alg {
340		case ECDSAP256SHA256:
341			intlen = 32
342		case ECDSAP384SHA384:
343			intlen = 48
344		}
345
346		signature := intToBytes(ecdsaSignature.R, intlen)
347		signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
348		return signature, nil
349
350	// There is no defined interface for what a DSA backed crypto.Signer returns
351	case DSA, DSANSEC3SHA1:
352		// 	t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
353		// 	signature := []byte{byte(t)}
354		// 	signature = append(signature, intToBytes(r1, 20)...)
355		// 	signature = append(signature, intToBytes(s1, 20)...)
356		// 	rr.Signature = signature
357	}
358
359	return nil, ErrAlg
360}
361
362// Verify validates an RRSet with the signature and key. This is only the
363// cryptographic test, the signature validity period must be checked separately.
364// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
365func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
366	// First the easy checks
367	if !IsRRset(rrset) {
368		return ErrRRset
369	}
370	if rr.KeyTag != k.KeyTag() {
371		return ErrKey
372	}
373	if rr.Hdr.Class != k.Hdr.Class {
374		return ErrKey
375	}
376	if rr.Algorithm != k.Algorithm {
377		return ErrKey
378	}
379	if strings.ToLower(rr.SignerName) != strings.ToLower(k.Hdr.Name) {
380		return ErrKey
381	}
382	if k.Protocol != 3 {
383		return ErrKey
384	}
385
386	// IsRRset checked that we have at least one RR and that the RRs in
387	// the set have consistent type, class, and name. Also check that type and
388	// class matches the RRSIG record.
389	if rrset[0].Header().Class != rr.Hdr.Class {
390		return ErrRRset
391	}
392	if rrset[0].Header().Rrtype != rr.TypeCovered {
393		return ErrRRset
394	}
395
396	// RFC 4035 5.3.2.  Reconstructing the Signed Data
397	// Copy the sig, except the rrsig data
398	sigwire := new(rrsigWireFmt)
399	sigwire.TypeCovered = rr.TypeCovered
400	sigwire.Algorithm = rr.Algorithm
401	sigwire.Labels = rr.Labels
402	sigwire.OrigTtl = rr.OrigTtl
403	sigwire.Expiration = rr.Expiration
404	sigwire.Inception = rr.Inception
405	sigwire.KeyTag = rr.KeyTag
406	sigwire.SignerName = strings.ToLower(rr.SignerName)
407	// Create the desired binary blob
408	signeddata := make([]byte, DefaultMsgSize)
409	n, err := packSigWire(sigwire, signeddata)
410	if err != nil {
411		return err
412	}
413	signeddata = signeddata[:n]
414	wire, err := rawSignatureData(rrset, rr)
415	if err != nil {
416		return err
417	}
418	signeddata = append(signeddata, wire...)
419
420	sigbuf := rr.sigBuf()           // Get the binary signature data
421	if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
422		// TODO(miek)
423		// remove the domain name and assume its ours?
424	}
425
426	hash, ok := AlgorithmToHash[rr.Algorithm]
427	if !ok {
428		return ErrAlg
429	}
430
431	switch rr.Algorithm {
432	case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, RSAMD5:
433		// TODO(mg): this can be done quicker, ie. cache the pubkey data somewhere??
434		pubkey := k.publicKeyRSA() // Get the key
435		if pubkey == nil {
436			return ErrKey
437		}
438
439		h := hash.New()
440		h.Write(signeddata)
441		return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
442
443	case ECDSAP256SHA256, ECDSAP384SHA384:
444		pubkey := k.publicKeyECDSA()
445		if pubkey == nil {
446			return ErrKey
447		}
448
449		// Split sigbuf into the r and s coordinates
450		r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
451		s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
452
453		h := hash.New()
454		h.Write(signeddata)
455		if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
456			return nil
457		}
458		return ErrSig
459
460	default:
461		return ErrAlg
462	}
463}
464
465// ValidityPeriod uses RFC1982 serial arithmetic to calculate
466// if a signature period is valid. If t is the zero time, the
467// current time is taken other t is. Returns true if the signature
468// is valid at the given time, otherwise returns false.
469func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
470	var utc int64
471	if t.IsZero() {
472		utc = time.Now().UTC().Unix()
473	} else {
474		utc = t.UTC().Unix()
475	}
476	modi := (int64(rr.Inception) - utc) / year68
477	mode := (int64(rr.Expiration) - utc) / year68
478	ti := int64(rr.Inception) + (modi * year68)
479	te := int64(rr.Expiration) + (mode * year68)
480	return ti <= utc && utc <= te
481}
482
483// Return the signatures base64 encodedig sigdata as a byte slice.
484func (rr *RRSIG) sigBuf() []byte {
485	sigbuf, err := fromBase64([]byte(rr.Signature))
486	if err != nil {
487		return nil
488	}
489	return sigbuf
490}
491
492// publicKeyRSA returns the RSA public key from a DNSKEY record.
493func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
494	keybuf, err := fromBase64([]byte(k.PublicKey))
495	if err != nil {
496		return nil
497	}
498
499	// RFC 2537/3110, section 2. RSA Public KEY Resource Records
500	// Length is in the 0th byte, unless its zero, then it
501	// it in bytes 1 and 2 and its a 16 bit number
502	explen := uint16(keybuf[0])
503	keyoff := 1
504	if explen == 0 {
505		explen = uint16(keybuf[1])<<8 | uint16(keybuf[2])
506		keyoff = 3
507	}
508	pubkey := new(rsa.PublicKey)
509
510	pubkey.N = big.NewInt(0)
511	shift := uint64((explen - 1) * 8)
512	expo := uint64(0)
513	for i := int(explen - 1); i > 0; i-- {
514		expo += uint64(keybuf[keyoff+i]) << shift
515		shift -= 8
516	}
517	// Remainder
518	expo += uint64(keybuf[keyoff])
519	if expo > 2<<31 {
520		// Larger expo than supported.
521		// println("dns: F5 primes (or larger) are not supported")
522		return nil
523	}
524	pubkey.E = int(expo)
525
526	pubkey.N.SetBytes(keybuf[keyoff+int(explen):])
527	return pubkey
528}
529
530// publicKeyECDSA returns the Curve public key from the DNSKEY record.
531func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey {
532	keybuf, err := fromBase64([]byte(k.PublicKey))
533	if err != nil {
534		return nil
535	}
536	pubkey := new(ecdsa.PublicKey)
537	switch k.Algorithm {
538	case ECDSAP256SHA256:
539		pubkey.Curve = elliptic.P256()
540		if len(keybuf) != 64 {
541			// wrongly encoded key
542			return nil
543		}
544	case ECDSAP384SHA384:
545		pubkey.Curve = elliptic.P384()
546		if len(keybuf) != 96 {
547			// Wrongly encoded key
548			return nil
549		}
550	}
551	pubkey.X = big.NewInt(0)
552	pubkey.X.SetBytes(keybuf[:len(keybuf)/2])
553	pubkey.Y = big.NewInt(0)
554	pubkey.Y.SetBytes(keybuf[len(keybuf)/2:])
555	return pubkey
556}
557
558func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey {
559	keybuf, err := fromBase64([]byte(k.PublicKey))
560	if err != nil {
561		return nil
562	}
563	if len(keybuf) < 22 {
564		return nil
565	}
566	t, keybuf := int(keybuf[0]), keybuf[1:]
567	size := 64 + t*8
568	q, keybuf := keybuf[:20], keybuf[20:]
569	if len(keybuf) != 3*size {
570		return nil
571	}
572	p, keybuf := keybuf[:size], keybuf[size:]
573	g, y := keybuf[:size], keybuf[size:]
574	pubkey := new(dsa.PublicKey)
575	pubkey.Parameters.Q = big.NewInt(0).SetBytes(q)
576	pubkey.Parameters.P = big.NewInt(0).SetBytes(p)
577	pubkey.Parameters.G = big.NewInt(0).SetBytes(g)
578	pubkey.Y = big.NewInt(0).SetBytes(y)
579	return pubkey
580}
581
582type wireSlice [][]byte
583
584func (p wireSlice) Len() int      { return len(p) }
585func (p wireSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
586func (p wireSlice) Less(i, j int) bool {
587	_, ioff, _ := UnpackDomainName(p[i], 0)
588	_, joff, _ := UnpackDomainName(p[j], 0)
589	return bytes.Compare(p[i][ioff+10:], p[j][joff+10:]) < 0
590}
591
592// Return the raw signature data.
593func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
594	wires := make(wireSlice, len(rrset))
595	for i, r := range rrset {
596		r1 := r.copy()
597		r1.Header().Ttl = s.OrigTtl
598		labels := SplitDomainName(r1.Header().Name)
599		// 6.2. Canonical RR Form. (4) - wildcards
600		if len(labels) > int(s.Labels) {
601			// Wildcard
602			r1.Header().Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "."
603		}
604		// RFC 4034: 6.2.  Canonical RR Form. (2) - domain name to lowercase
605		r1.Header().Name = strings.ToLower(r1.Header().Name)
606		// 6.2. Canonical RR Form. (3) - domain rdata to lowercase.
607		//   NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
608		//   HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
609		//   SRV, DNAME, A6
610		//
611		// RFC 6840 - Clarifications and Implementation Notes for DNS Security (DNSSEC):
612		//	Section 6.2 of [RFC4034] also erroneously lists HINFO as a record
613		//	that needs conversion to lowercase, and twice at that.  Since HINFO
614		//	records contain no domain names, they are not subject to case
615		//	conversion.
616		switch x := r1.(type) {
617		case *NS:
618			x.Ns = strings.ToLower(x.Ns)
619		case *CNAME:
620			x.Target = strings.ToLower(x.Target)
621		case *SOA:
622			x.Ns = strings.ToLower(x.Ns)
623			x.Mbox = strings.ToLower(x.Mbox)
624		case *MB:
625			x.Mb = strings.ToLower(x.Mb)
626		case *MG:
627			x.Mg = strings.ToLower(x.Mg)
628		case *MR:
629			x.Mr = strings.ToLower(x.Mr)
630		case *PTR:
631			x.Ptr = strings.ToLower(x.Ptr)
632		case *MINFO:
633			x.Rmail = strings.ToLower(x.Rmail)
634			x.Email = strings.ToLower(x.Email)
635		case *MX:
636			x.Mx = strings.ToLower(x.Mx)
637		case *NAPTR:
638			x.Replacement = strings.ToLower(x.Replacement)
639		case *KX:
640			x.Exchanger = strings.ToLower(x.Exchanger)
641		case *SRV:
642			x.Target = strings.ToLower(x.Target)
643		case *DNAME:
644			x.Target = strings.ToLower(x.Target)
645		}
646		// 6.2. Canonical RR Form. (5) - origTTL
647		wire := make([]byte, r1.len()+1) // +1 to be safe(r)
648		off, err1 := PackRR(r1, wire, 0, nil, false)
649		if err1 != nil {
650			return nil, err1
651		}
652		wire = wire[:off]
653		wires[i] = wire
654	}
655	sort.Sort(wires)
656	for i, wire := range wires {
657		if i > 0 && bytes.Equal(wire, wires[i-1]) {
658			continue
659		}
660		buf = append(buf, wire...)
661	}
662	return buf, nil
663}
664
665func packSigWire(sw *rrsigWireFmt, msg []byte) (int, error) {
666	// copied from zmsg.go RRSIG packing
667	off, err := packUint16(sw.TypeCovered, msg, 0)
668	if err != nil {
669		return off, err
670	}
671	off, err = packUint8(sw.Algorithm, msg, off)
672	if err != nil {
673		return off, err
674	}
675	off, err = packUint8(sw.Labels, msg, off)
676	if err != nil {
677		return off, err
678	}
679	off, err = packUint32(sw.OrigTtl, msg, off)
680	if err != nil {
681		return off, err
682	}
683	off, err = packUint32(sw.Expiration, msg, off)
684	if err != nil {
685		return off, err
686	}
687	off, err = packUint32(sw.Inception, msg, off)
688	if err != nil {
689		return off, err
690	}
691	off, err = packUint16(sw.KeyTag, msg, off)
692	if err != nil {
693		return off, err
694	}
695	off, err = PackDomainName(sw.SignerName, msg, off, nil, false)
696	if err != nil {
697		return off, err
698	}
699	return off, nil
700}
701
702func packKeyWire(dw *dnskeyWireFmt, msg []byte) (int, error) {
703	// copied from zmsg.go DNSKEY packing
704	off, err := packUint16(dw.Flags, msg, 0)
705	if err != nil {
706		return off, err
707	}
708	off, err = packUint8(dw.Protocol, msg, off)
709	if err != nil {
710		return off, err
711	}
712	off, err = packUint8(dw.Algorithm, msg, off)
713	if err != nil {
714		return off, err
715	}
716	off, err = packStringBase64(dw.PublicKey, msg, off)
717	if err != nil {
718		return off, err
719	}
720	return off, nil
721}
722