Skip to content

Commit 05140a3

Browse files
authored
Add indentityHash for algos that don't need hashing (miekg#1340)
This adds hash.go and creates a identityHash that is used for algorithms that do their own hashing (ED25519) for instance. This unifies the hash variable naming between dnssec and sig(0) signing and removes the special casing that existed for ED25519. This unifies the variable naming between sig(0) and dnssec signing and verifying. I didn't want to used crypto.RegisterHash as not to fiddle with the global namespaces of hashes, so the value of '0' from AlgorithmsToHash is handled specially in dnssec and sig(0) code. Note that ED448 isn't implemented at all. Signed-off-by: Miek Gieben <[email protected]>
1 parent af1ebf5 commit 05140a3

File tree

4 files changed

+78
-66
lines changed

4 files changed

+78
-66
lines changed

Diff for: dnssec.go

+13-29
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ var AlgorithmToString = map[uint8]string{
6565
}
6666

6767
// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
68+
// For newer algorithm that do their own hashing (i.e. ED25519) the returned value
69+
// is 0, implying no (external) hashing should occur. The non-exported identityHash is then
70+
// used.
6871
var AlgorithmToHash = map[uint8]crypto.Hash{
6972
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
7073
DSA: crypto.SHA1,
@@ -74,7 +77,7 @@ var AlgorithmToHash = map[uint8]crypto.Hash{
7477
ECDSAP256SHA256: crypto.SHA256,
7578
ECDSAP384SHA384: crypto.SHA384,
7679
RSASHA512: crypto.SHA512,
77-
ED25519: crypto.Hash(0),
80+
ED25519: 0,
7881
}
7982

8083
// DNSSEC hashing algorithm codes.
@@ -296,35 +299,20 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
296299
return err
297300
}
298301

299-
hash, ok := AlgorithmToHash[rr.Algorithm]
300-
if !ok {
301-
return ErrAlg
302+
h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
303+
if err != nil {
304+
return err
302305
}
303306

304307
switch rr.Algorithm {
305-
case ED25519:
306-
// ed25519 signs the raw message and performs hashing internally.
307-
// All other supported signature schemes operate over the pre-hashed
308-
// message, and thus ed25519 must be handled separately here.
309-
//
310-
// The raw message is passed directly into sign and crypto.Hash(0) is
311-
// used to signal to the crypto.Signer that the data has not been hashed.
312-
signature, err := sign(k, append(signdata, wire...), crypto.Hash(0), rr.Algorithm)
313-
if err != nil {
314-
return err
315-
}
316-
317-
rr.Signature = toBase64(signature)
318-
return nil
319308
case RSAMD5, DSA, DSANSEC3SHA1:
320309
// See RFC 6944.
321310
return ErrAlg
322311
default:
323-
h := hash.New()
324312
h.Write(signdata)
325313
h.Write(wire)
326314

327-
signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
315+
signature, err := sign(k, h.Sum(nil), cryptohash, rr.Algorithm)
328316
if err != nil {
329317
return err
330318
}
@@ -341,7 +329,7 @@ func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte,
341329
}
342330

343331
switch alg {
344-
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
332+
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, ED25519:
345333
return signature, nil
346334
case ECDSAP256SHA256, ECDSAP384SHA384:
347335
ecdsaSignature := &struct {
@@ -362,8 +350,6 @@ func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte,
362350
signature := intToBytes(ecdsaSignature.R, intlen)
363351
signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
364352
return signature, nil
365-
case ED25519:
366-
return signature, nil
367353
default:
368354
return nil, ErrAlg
369355
}
@@ -437,9 +423,9 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
437423
// remove the domain name and assume its ours?
438424
}
439425

440-
hash, ok := AlgorithmToHash[rr.Algorithm]
441-
if !ok {
442-
return ErrAlg
426+
h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
427+
if err != nil {
428+
return err
443429
}
444430

445431
switch rr.Algorithm {
@@ -450,10 +436,9 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
450436
return ErrKey
451437
}
452438

453-
h := hash.New()
454439
h.Write(signeddata)
455440
h.Write(wire)
456-
return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
441+
return rsa.VerifyPKCS1v15(pubkey, cryptohash, h.Sum(nil), sigbuf)
457442

458443
case ECDSAP256SHA256, ECDSAP384SHA384:
459444
pubkey := k.publicKeyECDSA()
@@ -465,7 +450,6 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
465450
r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
466451
s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
467452

468-
h := hash.New()
469453
h.Write(signeddata)
470454
h.Write(wire)
471455
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {

Diff for: hash.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package dns
2+
3+
import (
4+
"bytes"
5+
"crypto"
6+
"hash"
7+
)
8+
9+
// identityHash will not hash, it only buffers the data written into it and returns it as-is.
10+
type identityHash struct {
11+
b *bytes.Buffer
12+
}
13+
14+
// Implement the hash.Hash interface.
15+
16+
func (i identityHash) Write(b []byte) (int, error) { return i.b.Write(b) }
17+
func (i identityHash) Size() int { return i.b.Len() }
18+
func (i identityHash) BlockSize() int { return 1024 }
19+
func (i identityHash) Reset() { i.b.Reset() }
20+
func (i identityHash) Sum(b []byte) []byte { return append(b, i.b.Bytes()...) }
21+
22+
func hashFromAlgorithm(alg uint8) (hash.Hash, crypto.Hash, error) {
23+
hashnumber, ok := AlgorithmToHash[alg]
24+
if !ok {
25+
return nil, 0, ErrAlg
26+
}
27+
if hashnumber == 0 {
28+
return identityHash{b: &bytes.Buffer{}}, hashnumber, nil
29+
}
30+
return hashnumber.New(), hashnumber, nil
31+
}

Diff for: sig0.go

+25-28
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dns
33
import (
44
"crypto"
55
"crypto/ecdsa"
6+
"crypto/ed25519"
67
"crypto/rsa"
78
"encoding/binary"
89
"math/big"
@@ -38,18 +39,17 @@ func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
3839
}
3940
buf = buf[:off:cap(buf)]
4041

41-
hash, ok := AlgorithmToHash[rr.Algorithm]
42-
if !ok {
43-
return nil, ErrAlg
42+
h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
43+
if err != nil {
44+
return nil, err
4445
}
4546

46-
hasher := hash.New()
4747
// Write SIG rdata
48-
hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
48+
h.Write(buf[len(mbuf)+1+2+2+4+2:])
4949
// Write message
50-
hasher.Write(buf[:len(mbuf)])
50+
h.Write(buf[:len(mbuf)])
5151

52-
signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm)
52+
signature, err := sign(k, h.Sum(nil), cryptohash, rr.Algorithm)
5353
if err != nil {
5454
return nil, err
5555
}
@@ -82,28 +82,17 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
8282
return ErrKey
8383
}
8484

85-
var hash crypto.Hash
86-
switch rr.Algorithm {
87-
case RSASHA1:
88-
hash = crypto.SHA1
89-
case RSASHA256, ECDSAP256SHA256:
90-
hash = crypto.SHA256
91-
case ECDSAP384SHA384:
92-
hash = crypto.SHA384
93-
case RSASHA512:
94-
hash = crypto.SHA512
95-
default:
96-
return ErrAlg
97-
}
98-
hasher := hash.New()
85+
h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
86+
if err != nil {
87+
return err
88+
}
9989

10090
buflen := len(buf)
10191
qdc := binary.BigEndian.Uint16(buf[4:])
10292
anc := binary.BigEndian.Uint16(buf[6:])
10393
auc := binary.BigEndian.Uint16(buf[8:])
10494
adc := binary.BigEndian.Uint16(buf[10:])
10595
offset := headerSize
106-
var err error
10796
for i := uint16(0); i < qdc && offset < buflen; i++ {
10897
_, offset, err = UnpackDomainName(buf, offset)
10998
if err != nil {
@@ -166,21 +155,21 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
166155
return &Error{err: "signer name doesn't match key name"}
167156
}
168157
sigend := offset
169-
hasher.Write(buf[sigstart:sigend])
170-
hasher.Write(buf[:10])
171-
hasher.Write([]byte{
158+
h.Write(buf[sigstart:sigend])
159+
h.Write(buf[:10])
160+
h.Write([]byte{
172161
byte((adc - 1) << 8),
173162
byte(adc - 1),
174163
})
175-
hasher.Write(buf[12:bodyend])
164+
h.Write(buf[12:bodyend])
176165

177-
hashed := hasher.Sum(nil)
166+
hashed := h.Sum(nil)
178167
sig := buf[sigend:]
179168
switch k.Algorithm {
180169
case RSASHA1, RSASHA256, RSASHA512:
181170
pk := k.publicKeyRSA()
182171
if pk != nil {
183-
return rsa.VerifyPKCS1v15(pk, hash, hashed, sig)
172+
return rsa.VerifyPKCS1v15(pk, cryptohash, hashed, sig)
184173
}
185174
case ECDSAP256SHA256, ECDSAP384SHA384:
186175
pk := k.publicKeyECDSA()
@@ -192,6 +181,14 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
192181
}
193182
return ErrSig
194183
}
184+
case ED25519:
185+
pk := k.publicKeyED25519()
186+
if pk != nil {
187+
if ed25519.Verify(pk, hashed, sig) {
188+
return nil
189+
}
190+
return ErrSig
191+
}
195192
}
196193
return ErrKeyAlg
197194
}

Diff for: sig0_test.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ func TestSIG0(t *testing.T) {
1212
}
1313
m := new(Msg)
1414
m.SetQuestion("example.org.", TypeSOA)
15-
for _, alg := range []uint8{ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256, RSASHA512} {
15+
for _, alg := range []uint8{ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256, RSASHA512, ED25519} {
1616
algstr := AlgorithmToString[alg]
1717
keyrr := new(KEY)
1818
keyrr.Hdr.Name = algstr + "."
@@ -21,7 +21,7 @@ func TestSIG0(t *testing.T) {
2121
keyrr.Algorithm = alg
2222
keysize := 512
2323
switch alg {
24-
case ECDSAP256SHA256:
24+
case ECDSAP256SHA256, ED25519:
2525
keysize = 256
2626
case ECDSAP384SHA384:
2727
keysize = 384
@@ -30,7 +30,7 @@ func TestSIG0(t *testing.T) {
3030
}
3131
pk, err := keyrr.Generate(keysize)
3232
if err != nil {
33-
t.Errorf("failed to generate key for “%s”: %v", algstr, err)
33+
t.Errorf("failed to generate key for %q: %v", algstr, err)
3434
continue
3535
}
3636
now := uint32(time.Now().Unix())
@@ -45,16 +45,16 @@ func TestSIG0(t *testing.T) {
4545
sigrr.SignerName = keyrr.Hdr.Name
4646
mb, err := sigrr.Sign(pk.(crypto.Signer), m)
4747
if err != nil {
48-
t.Errorf("failed to sign message using “%s”: %v", algstr, err)
48+
t.Errorf("failed to sign message using %q: %v", algstr, err)
4949
continue
5050
}
5151
m := new(Msg)
5252
if err := m.Unpack(mb); err != nil {
53-
t.Errorf("failed to unpack message signed using “%s”: %v", algstr, err)
53+
t.Errorf("failed to unpack message signed using %q: %v", algstr, err)
5454
continue
5555
}
5656
if len(m.Extra) != 1 {
57-
t.Errorf("missing SIG for message signed using “%s”", algstr)
57+
t.Errorf("missing SIG for message signed using %q", algstr)
5858
continue
5959
}
6060
var sigrrwire *SIG
@@ -71,20 +71,20 @@ func TestSIG0(t *testing.T) {
7171
id = "sigrrwire"
7272
}
7373
if err := rr.Verify(keyrr, mb); err != nil {
74-
t.Errorf("failed to verify “%s” signed SIG(%s): %v", algstr, id, err)
74+
t.Errorf("failed to verify %q signed SIG(%s): %v", algstr, id, err)
7575
continue
7676
}
7777
}
7878
mb[13]++
7979
if err := sigrr.Verify(keyrr, mb); err == nil {
80-
t.Errorf("verify succeeded on an altered message using “%s”", algstr)
80+
t.Errorf("verify succeeded on an altered message using %q", algstr)
8181
continue
8282
}
8383
sigrr.Expiration = 2
8484
sigrr.Inception = 1
8585
mb, _ = sigrr.Sign(pk.(crypto.Signer), m)
8686
if err := sigrr.Verify(keyrr, mb); err == nil {
87-
t.Errorf("verify succeeded on an expired message using “%s”", algstr)
87+
t.Errorf("verify succeeded on an expired message using %q", algstr)
8888
continue
8989
}
9090
}

0 commit comments

Comments
 (0)