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