sig0.go raw

   1  package dns
   2  
   3  import (
   4  	"crypto"
   5  	"crypto/ecdsa"
   6  	"crypto/ed25519"
   7  	"crypto/rsa"
   8  	"encoding/binary"
   9  	"math/big"
  10  	"time"
  11  )
  12  
  13  // Sign signs a dns.Msg. It fills the signature with the appropriate data.
  14  // The SIG record should have the SignerName, KeyTag, Algorithm, Inception
  15  // and Expiration set.
  16  func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
  17  	if k == nil {
  18  		return nil, ErrPrivKey
  19  	}
  20  	if rr.KeyTag == 0 || rr.SignerName == "" || rr.Algorithm == 0 {
  21  		return nil, ErrKey
  22  	}
  23  
  24  	rr.Hdr = RR_Header{Name: ".", Rrtype: TypeSIG, Class: ClassANY, Ttl: 0}
  25  	rr.OrigTtl, rr.TypeCovered, rr.Labels = 0, 0, 0
  26  
  27  	buf := make([]byte, m.Len()+Len(rr))
  28  	mbuf, err := m.PackBuffer(buf)
  29  	if err != nil {
  30  		return nil, err
  31  	}
  32  	if &buf[0] != &mbuf[0] {
  33  		return nil, ErrBuf
  34  	}
  35  	off, err := PackRR(rr, buf, len(mbuf), nil, false)
  36  	if err != nil {
  37  		return nil, err
  38  	}
  39  	buf = buf[:off:cap(buf)]
  40  
  41  	h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
  42  	if err != nil {
  43  		return nil, err
  44  	}
  45  
  46  	// Write SIG rdata
  47  	h.Write(buf[len(mbuf)+1+2+2+4+2:])
  48  	// Write message
  49  	h.Write(buf[:len(mbuf)])
  50  
  51  	signature, err := sign(k, h.Sum(nil), cryptohash, rr.Algorithm)
  52  	if err != nil {
  53  		return nil, err
  54  	}
  55  
  56  	rr.Signature = toBase64(signature)
  57  
  58  	buf = append(buf, signature...)
  59  	if len(buf) > int(^uint16(0)) {
  60  		return nil, ErrBuf
  61  	}
  62  	// Adjust sig data length
  63  	rdoff := len(mbuf) + 1 + 2 + 2 + 4
  64  	rdlen := binary.BigEndian.Uint16(buf[rdoff:])
  65  	rdlen += uint16(len(signature))
  66  	binary.BigEndian.PutUint16(buf[rdoff:], rdlen)
  67  	// Adjust additional count
  68  	adc := binary.BigEndian.Uint16(buf[10:])
  69  	adc++
  70  	binary.BigEndian.PutUint16(buf[10:], adc)
  71  	return buf, nil
  72  }
  73  
  74  // Verify validates the message buf using the key k.
  75  // It's assumed that buf is a valid message from which rr was unpacked.
  76  func (rr *SIG) Verify(k *KEY, buf []byte) error {
  77  	if k == nil {
  78  		return ErrKey
  79  	}
  80  	if rr.KeyTag == 0 || rr.SignerName == "" || rr.Algorithm == 0 {
  81  		return ErrKey
  82  	}
  83  
  84  	h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
  85  	if err != nil {
  86  		return err
  87  	}
  88  
  89  	buflen := len(buf)
  90  	qdc := binary.BigEndian.Uint16(buf[4:])
  91  	anc := binary.BigEndian.Uint16(buf[6:])
  92  	auc := binary.BigEndian.Uint16(buf[8:])
  93  	adc := binary.BigEndian.Uint16(buf[10:])
  94  	offset := headerSize
  95  	for i := uint16(0); i < qdc && offset < buflen; i++ {
  96  		_, offset, err = UnpackDomainName(buf, offset)
  97  		if err != nil {
  98  			return err
  99  		}
 100  		// Skip past Type and Class
 101  		offset += 2 + 2
 102  	}
 103  	for i := uint16(1); i < anc+auc+adc && offset < buflen; i++ {
 104  		_, offset, err = UnpackDomainName(buf, offset)
 105  		if err != nil {
 106  			return err
 107  		}
 108  		// Skip past Type, Class and TTL
 109  		offset += 2 + 2 + 4
 110  		if offset+1 >= buflen {
 111  			continue
 112  		}
 113  		rdlen := binary.BigEndian.Uint16(buf[offset:])
 114  		offset += 2
 115  		offset += int(rdlen)
 116  	}
 117  	if offset >= buflen {
 118  		return &Error{err: "overflowing unpacking signed message"}
 119  	}
 120  
 121  	// offset should be just prior to SIG
 122  	bodyend := offset
 123  	// owner name SHOULD be root
 124  	_, offset, err = UnpackDomainName(buf, offset)
 125  	if err != nil {
 126  		return err
 127  	}
 128  	// Skip Type, Class, TTL, RDLen
 129  	offset += 2 + 2 + 4 + 2
 130  	sigstart := offset
 131  	// Skip Type Covered, Algorithm, Labels, Original TTL
 132  	offset += 2 + 1 + 1 + 4
 133  	if offset+4+4 >= buflen {
 134  		return &Error{err: "overflow unpacking signed message"}
 135  	}
 136  	expire := binary.BigEndian.Uint32(buf[offset:])
 137  	offset += 4
 138  	incept := binary.BigEndian.Uint32(buf[offset:])
 139  	offset += 4
 140  	now := uint32(time.Now().Unix())
 141  	if now < incept || now > expire {
 142  		return ErrTime
 143  	}
 144  	// Skip key tag
 145  	offset += 2
 146  	var signername string
 147  	signername, offset, err = UnpackDomainName(buf, offset)
 148  	if err != nil {
 149  		return err
 150  	}
 151  	// If key has come from the DNS name compression might
 152  	// have mangled the case of the name
 153  	if !equal(signername, k.Header().Name) {
 154  		return &Error{err: "signer name doesn't match key name"}
 155  	}
 156  	sigend := offset
 157  	h.Write(buf[sigstart:sigend])
 158  	h.Write(buf[:10])
 159  	h.Write([]byte{
 160  		byte((adc - 1) << 8),
 161  		byte(adc - 1),
 162  	})
 163  	h.Write(buf[12:bodyend])
 164  
 165  	hashed := h.Sum(nil)
 166  	sig := buf[sigend:]
 167  	switch k.Algorithm {
 168  	case RSASHA1, RSASHA256, RSASHA512:
 169  		pk := k.publicKeyRSA()
 170  		if pk != nil {
 171  			return rsa.VerifyPKCS1v15(pk, cryptohash, hashed, sig)
 172  		}
 173  	case ECDSAP256SHA256, ECDSAP384SHA384:
 174  		pk := k.publicKeyECDSA()
 175  		r := new(big.Int).SetBytes(sig[:len(sig)/2])
 176  		s := new(big.Int).SetBytes(sig[len(sig)/2:])
 177  		if pk != nil {
 178  			if ecdsa.Verify(pk, hashed, r, s) {
 179  				return nil
 180  			}
 181  			return ErrSig
 182  		}
 183  	case ED25519:
 184  		pk := k.publicKeyED25519()
 185  		if pk != nil {
 186  			if ed25519.Verify(pk, hashed, sig) {
 187  				return nil
 188  			}
 189  			return ErrSig
 190  		}
 191  	}
 192  	return ErrKeyAlg
 193  }
 194