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 rdlen := binary.BigEndian.Uint16(buf[offset:]) 131 offset += 2 132 offset += int(rdlen) 133 } 134 if offset >= buflen { 135 return &Error{err: "overflowing unpacking signed message"} 136 } 137 138 // offset should be just prior to SIG 139 bodyend := offset 140 // owner name SHOULD be root 141 _, offset, err = UnpackDomainName(buf, offset) 142 if err != nil { 143 return err 144 } 145 // Skip Type, Class, TTL, RDLen 146 offset += 2 + 2 + 4 + 2 147 sigstart := offset 148 // Skip Type Covered, Algorithm, Labels, Original TTL 149 offset += 2 + 1 + 1 + 4 150 if offset+4+4 >= buflen { 151 return &Error{err: "overflow unpacking signed message"} 152 } 153 expire := binary.BigEndian.Uint32(buf[offset:]) 154 offset += 4 155 incept := binary.BigEndian.Uint32(buf[offset:]) 156 offset += 4 157 now := uint32(time.Now().Unix()) 158 if now < incept || now > expire { 159 return ErrTime 160 } 161 // Skip key tag 162 offset += 2 163 var signername string 164 signername, offset, err = UnpackDomainName(buf, offset) 165 if err != nil { 166 return err 167 } 168 // If key has come from the DNS name compression might 169 // have mangled the case of the name 170 if strings.ToLower(signername) != strings.ToLower(k.Header().Name) { 171 return &Error{err: "signer name doesn't match key name"} 172 } 173 sigend := offset 174 hasher.Write(buf[sigstart:sigend]) 175 hasher.Write(buf[:10]) 176 hasher.Write([]byte{ 177 byte((adc - 1) << 8), 178 byte(adc - 1), 179 }) 180 hasher.Write(buf[12:bodyend]) 181 182 hashed := hasher.Sum(nil) 183 sig := buf[sigend:] 184 switch k.Algorithm { 185 case DSA: 186 pk := k.publicKeyDSA() 187 sig = sig[1:] 188 r := big.NewInt(0) 189 r.SetBytes(sig[:len(sig)/2]) 190 s := big.NewInt(0) 191 s.SetBytes(sig[len(sig)/2:]) 192 if pk != nil { 193 if dsa.Verify(pk, hashed, r, s) { 194 return nil 195 } 196 return ErrSig 197 } 198 case RSASHA1, RSASHA256, RSASHA512: 199 pk := k.publicKeyRSA() 200 if pk != nil { 201 return rsa.VerifyPKCS1v15(pk, hash, hashed, sig) 202 } 203 case ECDSAP256SHA256, ECDSAP384SHA384: 204 pk := k.publicKeyECDSA() 205 r := big.NewInt(0) 206 r.SetBytes(sig[:len(sig)/2]) 207 s := big.NewInt(0) 208 s.SetBytes(sig[len(sig)/2:]) 209 if pk != nil { 210 if ecdsa.Verify(pk, hashed, r, s) { 211 return nil 212 } 213 return ErrSig 214 } 215 } 216 return ErrKeyAlg 217} 218