...

Source file src/github.com/miekg/dns/sig0.go

Documentation: github.com/miekg/dns

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

View as plain text