package dns

import (
	
	
	
	
	
	
	
)

// Sign signs a dns.Msg. It fills the signature with the appropriate data.
// The SIG record should have the SignerName, KeyTag, Algorithm, Inception
// and Expiration set.
func ( *SIG) ( crypto.Signer,  *Msg) ([]byte, error) {
	if  == nil {
		return nil, ErrPrivKey
	}
	if .KeyTag == 0 || .SignerName == "" || .Algorithm == 0 {
		return nil, ErrKey
	}

	.Hdr = RR_Header{Name: ".", Rrtype: TypeSIG, Class: ClassANY, Ttl: 0}
	.OrigTtl, .TypeCovered, .Labels = 0, 0, 0

	 := make([]byte, .Len()+Len())
	,  := .PackBuffer()
	if  != nil {
		return nil, 
	}
	if &[0] != &[0] {
		return nil, ErrBuf
	}
	,  := PackRR(, , len(), nil, false)
	if  != nil {
		return nil, 
	}
	 = [::cap()]

	, ,  := hashFromAlgorithm(.Algorithm)
	if  != nil {
		return nil, 
	}

	// Write SIG rdata
	.Write([len()+1+2+2+4+2:])
	// Write message
	.Write([:len()])

	,  := sign(, .Sum(nil), , .Algorithm)
	if  != nil {
		return nil, 
	}

	.Signature = toBase64()

	 = append(, ...)
	if len() > int(^uint16(0)) {
		return nil, ErrBuf
	}
	// Adjust sig data length
	 := len() + 1 + 2 + 2 + 4
	 := binary.BigEndian.Uint16([:])
	 += uint16(len())
	binary.BigEndian.PutUint16([:], )
	// Adjust additional count
	 := binary.BigEndian.Uint16([10:])
	++
	binary.BigEndian.PutUint16([10:], )
	return , nil
}

// Verify validates the message buf using the key k.
// It's assumed that buf is a valid message from which rr was unpacked.
func ( *SIG) ( *KEY,  []byte) error {
	if  == nil {
		return ErrKey
	}
	if .KeyTag == 0 || .SignerName == "" || .Algorithm == 0 {
		return ErrKey
	}

	, ,  := hashFromAlgorithm(.Algorithm)
	if  != nil {
		return 
	}

	 := len()
	 := binary.BigEndian.Uint16([4:])
	 := binary.BigEndian.Uint16([6:])
	 := binary.BigEndian.Uint16([8:])
	 := binary.BigEndian.Uint16([10:])
	 := headerSize
	for  := uint16(0);  <  &&  < ; ++ {
		_, ,  = UnpackDomainName(, )
		if  != nil {
			return 
		}
		// Skip past Type and Class
		 += 2 + 2
	}
	for  := uint16(1);  < ++ &&  < ; ++ {
		_, ,  = UnpackDomainName(, )
		if  != nil {
			return 
		}
		// Skip past Type, Class and TTL
		 += 2 + 2 + 4
		if +1 >=  {
			continue
		}
		 := binary.BigEndian.Uint16([:])
		 += 2
		 += int()
	}
	if  >=  {
		return &Error{err: "overflowing unpacking signed message"}
	}

	// offset should be just prior to SIG
	 := 
	// owner name SHOULD be root
	_, ,  = UnpackDomainName(, )
	if  != nil {
		return 
	}
	// Skip Type, Class, TTL, RDLen
	 += 2 + 2 + 4 + 2
	 := 
	// Skip Type Covered, Algorithm, Labels, Original TTL
	 += 2 + 1 + 1 + 4
	if +4+4 >=  {
		return &Error{err: "overflow unpacking signed message"}
	}
	 := binary.BigEndian.Uint32([:])
	 += 4
	 := binary.BigEndian.Uint32([:])
	 += 4
	 := uint32(time.Now().Unix())
	if  <  ||  >  {
		return ErrTime
	}
	// Skip key tag
	 += 2
	var  string
	, ,  = UnpackDomainName(, )
	if  != nil {
		return 
	}
	// If key has come from the DNS name compression might
	// have mangled the case of the name
	if !equal(, .Header().Name) {
		return &Error{err: "signer name doesn't match key name"}
	}
	 := 
	.Write([:])
	.Write([:10])
	.Write([]byte{
		byte(( - 1) << 8),
		byte( - 1),
	})
	.Write([12:])

	 := .Sum(nil)
	 := [:]
	switch .Algorithm {
	case RSASHA1, RSASHA256, RSASHA512:
		 := .publicKeyRSA()
		if  != nil {
			return rsa.VerifyPKCS1v15(, , , )
		}
	case ECDSAP256SHA256, ECDSAP384SHA384:
		 := .publicKeyECDSA()
		 := new(big.Int).SetBytes([:len()/2])
		 := new(big.Int).SetBytes([len()/2:])
		if  != nil {
			if ecdsa.Verify(, , , ) {
				return nil
			}
			return ErrSig
		}
	case ED25519:
		 := .publicKeyED25519()
		if  != nil {
			if ed25519.Verify(, , ) {
				return nil
			}
			return ErrSig
		}
	}
	return ErrKeyAlg
}