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