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