1package dns 2 3import ( 4 "crypto" 5 "crypto/ecdsa" 6 "crypto/rsa" 7 "encoding/binary" 8 "math/big" 9 "strings" 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. 16func (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 hash, ok := AlgorithmToHash[rr.Algorithm] 42 if !ok { 43 return nil, ErrAlg 44 } 45 46 hasher := hash.New() 47 // Write SIG rdata 48 hasher.Write(buf[len(mbuf)+1+2+2+4+2:]) 49 // Write message 50 hasher.Write(buf[:len(mbuf)]) 51 52 signature, err := sign(k, hasher.Sum(nil), hash, 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. 77func (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 var hash crypto.Hash 86 switch rr.Algorithm { 87 case RSASHA1: 88 hash = crypto.SHA1 89 case RSASHA256, ECDSAP256SHA256: 90 hash = crypto.SHA256 91 case ECDSAP384SHA384: 92 hash = crypto.SHA384 93 case RSASHA512: 94 hash = crypto.SHA512 95 default: 96 return ErrAlg 97 } 98 hasher := hash.New() 99 100 buflen := len(buf) 101 qdc := binary.BigEndian.Uint16(buf[4:]) 102 anc := binary.BigEndian.Uint16(buf[6:]) 103 auc := binary.BigEndian.Uint16(buf[8:]) 104 adc := binary.BigEndian.Uint16(buf[10:]) 105 offset := headerSize 106 var err error 107 for i := uint16(0); i < qdc && offset < buflen; i++ { 108 _, offset, err = UnpackDomainName(buf, offset) 109 if err != nil { 110 return err 111 } 112 // Skip past Type and Class 113 offset += 2 + 2 114 } 115 for i := uint16(1); i < anc+auc+adc && offset < buflen; i++ { 116 _, offset, err = UnpackDomainName(buf, offset) 117 if err != nil { 118 return err 119 } 120 // Skip past Type, Class and TTL 121 offset += 2 + 2 + 4 122 if offset+1 >= buflen { 123 continue 124 } 125 rdlen := binary.BigEndian.Uint16(buf[offset:]) 126 offset += 2 127 offset += int(rdlen) 128 } 129 if offset >= buflen { 130 return &Error{err: "overflowing unpacking signed message"} 131 } 132 133 // offset should be just prior to SIG 134 bodyend := offset 135 // owner name SHOULD be root 136 _, offset, err = UnpackDomainName(buf, offset) 137 if err != nil { 138 return err 139 } 140 // Skip Type, Class, TTL, RDLen 141 offset += 2 + 2 + 4 + 2 142 sigstart := offset 143 // Skip Type Covered, Algorithm, Labels, Original TTL 144 offset += 2 + 1 + 1 + 4 145 if offset+4+4 >= buflen { 146 return &Error{err: "overflow unpacking signed message"} 147 } 148 expire := binary.BigEndian.Uint32(buf[offset:]) 149 offset += 4 150 incept := binary.BigEndian.Uint32(buf[offset:]) 151 offset += 4 152 now := uint32(time.Now().Unix()) 153 if now < incept || now > expire { 154 return ErrTime 155 } 156 // Skip key tag 157 offset += 2 158 var signername string 159 signername, offset, err = UnpackDomainName(buf, offset) 160 if err != nil { 161 return err 162 } 163 // If key has come from the DNS name compression might 164 // have mangled the case of the name 165 if !strings.EqualFold(signername, k.Header().Name) { 166 return &Error{err: "signer name doesn't match key name"} 167 } 168 sigend := offset 169 hasher.Write(buf[sigstart:sigend]) 170 hasher.Write(buf[:10]) 171 hasher.Write([]byte{ 172 byte((adc - 1) << 8), 173 byte(adc - 1), 174 }) 175 hasher.Write(buf[12:bodyend]) 176 177 hashed := hasher.Sum(nil) 178 sig := buf[sigend:] 179 switch k.Algorithm { 180 case RSASHA1, RSASHA256, RSASHA512: 181 pk := k.publicKeyRSA() 182 if pk != nil { 183 return rsa.VerifyPKCS1v15(pk, hash, hashed, sig) 184 } 185 case ECDSAP256SHA256, ECDSAP384SHA384: 186 pk := k.publicKeyECDSA() 187 r := new(big.Int).SetBytes(sig[:len(sig)/2]) 188 s := new(big.Int).SetBytes(sig[len(sig)/2:]) 189 if pk != nil { 190 if ecdsa.Verify(pk, hashed, r, s) { 191 return nil 192 } 193 return ErrSig 194 } 195 } 196 return ErrKeyAlg 197} 198