1package dns 2 3import ( 4 "crypto" 5 "crypto/dsa" 6 "crypto/ecdsa" 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. 17func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) { 18 if k == nil { 19 return nil, ErrPrivKey 20 } 21 if rr.KeyTag == 0 || len(rr.SignerName) == 0 || 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 hash, ok := AlgorithmToHash[rr.Algorithm] 43 if !ok { 44 return nil, ErrAlg 45 } 46 47 hasher := hash.New() 48 // Write SIG rdata 49 hasher.Write(buf[len(mbuf)+1+2+2+4+2:]) 50 // Write message 51 hasher.Write(buf[:len(mbuf)]) 52 53 signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm) 54 if err != nil { 55 return nil, err 56 } 57 58 rr.Signature = toBase64(signature) 59 60 buf = append(buf, signature...) 61 if len(buf) > int(^uint16(0)) { 62 return nil, ErrBuf 63 } 64 // Adjust sig data length 65 rdoff := len(mbuf) + 1 + 2 + 2 + 4 66 rdlen := binary.BigEndian.Uint16(buf[rdoff:]) 67 rdlen += uint16(len(signature)) 68 binary.BigEndian.PutUint16(buf[rdoff:], rdlen) 69 // Adjust additional count 70 adc := binary.BigEndian.Uint16(buf[10:]) 71 adc++ 72 binary.BigEndian.PutUint16(buf[10:], adc) 73 return buf, nil 74} 75 76// Verify validates the message buf using the key k. 77// It's assumed that buf is a valid message from which rr was unpacked. 78func (rr *SIG) Verify(k *KEY, buf []byte) error { 79 if k == nil { 80 return ErrKey 81 } 82 if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 { 83 return ErrKey 84 } 85 86 var hash crypto.Hash 87 switch rr.Algorithm { 88 case DSA, RSASHA1: 89 hash = crypto.SHA1 90 case RSASHA256, ECDSAP256SHA256: 91 hash = crypto.SHA256 92 case ECDSAP384SHA384: 93 hash = crypto.SHA384 94 case RSASHA512: 95 hash = crypto.SHA512 96 default: 97 return ErrAlg 98 } 99 hasher := hash.New() 100 101 buflen := len(buf) 102 qdc := binary.BigEndian.Uint16(buf[4:]) 103 anc := binary.BigEndian.Uint16(buf[6:]) 104 auc := binary.BigEndian.Uint16(buf[8:]) 105 adc := binary.BigEndian.Uint16(buf[10:]) 106 offset := headerSize 107 var err error 108 for i := uint16(0); i < qdc && offset < buflen; i++ { 109 _, offset, err = UnpackDomainName(buf, offset) 110 if err != nil { 111 return err 112 } 113 // Skip past Type and Class 114 offset += 2 + 2 115 } 116 for i := uint16(1); i < anc+auc+adc && offset < buflen; i++ { 117 _, offset, err = UnpackDomainName(buf, offset) 118 if err != nil { 119 return err 120 } 121 // Skip past Type, Class and TTL 122 offset += 2 + 2 + 4 123 if offset+1 >= buflen { 124 continue 125 } 126 rdlen := binary.BigEndian.Uint16(buf[offset:]) 127 offset += 2 128 offset += int(rdlen) 129 } 130 if offset >= buflen { 131 return &Error{err: "overflowing unpacking signed message"} 132 } 133 134 // offset should be just prior to SIG 135 bodyend := offset 136 // owner name SHOULD be root 137 _, offset, err = UnpackDomainName(buf, offset) 138 if err != nil { 139 return err 140 } 141 // Skip Type, Class, TTL, RDLen 142 offset += 2 + 2 + 4 + 2 143 sigstart := offset 144 // Skip Type Covered, Algorithm, Labels, Original TTL 145 offset += 2 + 1 + 1 + 4 146 if offset+4+4 >= buflen { 147 return &Error{err: "overflow unpacking signed message"} 148 } 149 expire := binary.BigEndian.Uint32(buf[offset:]) 150 offset += 4 151 incept := binary.BigEndian.Uint32(buf[offset:]) 152 offset += 4 153 now := uint32(time.Now().Unix()) 154 if now < incept || now > expire { 155 return ErrTime 156 } 157 // Skip key tag 158 offset += 2 159 var signername string 160 signername, offset, err = UnpackDomainName(buf, offset) 161 if err != nil { 162 return err 163 } 164 // If key has come from the DNS name compression might 165 // have mangled the case of the name 166 if !strings.EqualFold(signername, k.Header().Name) { 167 return &Error{err: "signer name doesn't match key name"} 168 } 169 sigend := offset 170 hasher.Write(buf[sigstart:sigend]) 171 hasher.Write(buf[:10]) 172 hasher.Write([]byte{ 173 byte((adc - 1) << 8), 174 byte(adc - 1), 175 }) 176 hasher.Write(buf[12:bodyend]) 177 178 hashed := hasher.Sum(nil) 179 sig := buf[sigend:] 180 switch k.Algorithm { 181 case DSA: 182 pk := k.publicKeyDSA() 183 sig = sig[1:] 184 r := new(big.Int).SetBytes(sig[:len(sig)/2]) 185 s := new(big.Int).SetBytes(sig[len(sig)/2:]) 186 if pk != nil { 187 if dsa.Verify(pk, hashed, r, s) { 188 return nil 189 } 190 return ErrSig 191 } 192 case RSASHA1, RSASHA256, RSASHA512: 193 pk := k.publicKeyRSA() 194 if pk != nil { 195 return rsa.VerifyPKCS1v15(pk, hash, hashed, sig) 196 } 197 case ECDSAP256SHA256, ECDSAP384SHA384: 198 pk := k.publicKeyECDSA() 199 r := new(big.Int).SetBytes(sig[:len(sig)/2]) 200 s := new(big.Int).SetBytes(sig[len(sig)/2:]) 201 if pk != nil { 202 if ecdsa.Verify(pk, hashed, r, s) { 203 return nil 204 } 205 return ErrSig 206 } 207 } 208 return ErrKeyAlg 209} 210