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