From 034c2472297c31e47588e50cac6979a9f54bda79 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 26 Mar 2015 15:34:52 -0700 Subject: [PATCH] Refactor DNSSEC to use crypto.{PrivateKey,Signer} This will allow RRSIG.Sign to use generic crypto.Signer implementations. This is a interface breaking change, even if the required changes are most likely just type asserions from crypto.PrivateKey to the underlying type or crypto.Signer. --- dnssec.go | 237 +++++++++++++++++++++++++--------------------- dnssec_keygen.go | 9 +- dnssec_keyscan.go | 11 ++- dnssec_privkey.go | 189 +++++++++++++----------------------- dnssec_test.go | 23 +++-- parse_test.go | 4 +- sig0.go | 25 ++--- sig0_test.go | 7 +- 8 files changed, 234 insertions(+), 271 deletions(-) diff --git a/dnssec.go b/dnssec.go index 1a993a0e..49ab4f1e 100644 --- a/dnssec.go +++ b/dnssec.go @@ -6,14 +6,14 @@ import ( "crypto/dsa" "crypto/ecdsa" "crypto/elliptic" - "crypto/md5" + _ "crypto/md5" + "crypto/rand" "crypto/rsa" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" + _ "crypto/sha1" + _ "crypto/sha256" + _ "crypto/sha512" + "encoding/asn1" "encoding/hex" - "hash" - "io" "math/big" "sort" "strings" @@ -42,6 +42,38 @@ const ( PRIVATEOID uint8 = 254 ) +// Map for algorithm names. +var AlgorithmToString = map[uint8]string{ + RSAMD5: "RSAMD5", + DH: "DH", + DSA: "DSA", + RSASHA1: "RSASHA1", + DSANSEC3SHA1: "DSA-NSEC3-SHA1", + RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1", + RSASHA256: "RSASHA256", + RSASHA512: "RSASHA512", + ECCGOST: "ECC-GOST", + ECDSAP256SHA256: "ECDSAP256SHA256", + ECDSAP384SHA384: "ECDSAP384SHA384", + INDIRECT: "INDIRECT", + PRIVATEDNS: "PRIVATEDNS", + PRIVATEOID: "PRIVATEOID", +} + +// Map of algorithm strings. +var StringToAlgorithm = reverseInt8(AlgorithmToString) + +// Map of algorithm crypto hashes. +var AlgorithmToHash = map[uint8]crypto.Hash{ + RSAMD5: crypto.MD5, // Deprecated in RFC 6725 + RSASHA1: crypto.SHA1, + RSASHA1NSEC3SHA1: crypto.SHA1, + RSASHA256: crypto.SHA256, + ECDSAP256SHA256: crypto.SHA256, + ECDSAP384SHA384: crypto.SHA384, + RSASHA512: crypto.SHA512, +} + // DNSSEC hashing algorithm codes. const ( _ uint8 = iota @@ -52,6 +84,18 @@ const ( SHA512 // Experimental ) +// Map for hash names. +var HashToString = map[uint8]string{ + SHA1: "SHA1", + SHA256: "SHA256", + GOST94: "GOST94", + SHA384: "SHA384", + SHA512: "SHA512", +} + +// Map of hash strings. +var StringToHash = reverseInt8(HashToString) + // DNSKEY flag values. const ( SEP = 1 @@ -168,24 +212,23 @@ func (k *DNSKEY) ToDS(h uint8) *DS { // digest buffer digest := append(owner, wire...) // another copy + var hash crypto.Hash switch h { case SHA1: - s := sha1.New() - io.WriteString(s, string(digest)) - ds.Digest = hex.EncodeToString(s.Sum(nil)) + hash = crypto.SHA1 case SHA256: - s := sha256.New() - io.WriteString(s, string(digest)) - ds.Digest = hex.EncodeToString(s.Sum(nil)) + hash = crypto.SHA256 case SHA384: - s := sha512.New384() - io.WriteString(s, string(digest)) - ds.Digest = hex.EncodeToString(s.Sum(nil)) - case GOST94: - /* I have no clue */ + hash = crypto.SHA384 + case SHA512: + hash = crypto.SHA512 default: return nil } + + s := hash.New() + s.Write(digest) + ds.Digest = hex.EncodeToString(s.Sum(nil)) return ds } @@ -212,7 +255,7 @@ func (d *DS) ToCDS() *CDS { // There is no check if RRSet is a proper (RFC 2181) RRSet. // If OrigTTL is non zero, it is used as-is, otherwise the TTL of the RRset // is used as the OrigTTL. -func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error { +func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error { if k == nil { return ErrPrivKey } @@ -258,39 +301,66 @@ func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error { } signdata = append(signdata, wire...) - var h hash.Hash - switch rr.Algorithm { - case DSA, DSANSEC3SHA1: - // TODO: this seems bugged, will panic - case RSASHA1, RSASHA1NSEC3SHA1: - h = sha1.New() - case RSASHA256, ECDSAP256SHA256: - h = sha256.New() - case ECDSAP384SHA384: - h = sha512.New384() - case RSASHA512: - h = sha512.New() - case RSAMD5: - fallthrough // Deprecated in RFC 6725 - default: + hash, ok := AlgorithmToHash[rr.Algorithm] + if !ok { return ErrAlg } - _, err = h.Write(signdata) - if err != nil { - return err - } - sighash := h.Sum(nil) + h := hash.New() + h.Write(signdata) - signature, err := k.Sign(sighash, rr.Algorithm) + signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm) if err != nil { return err } + rr.Signature = toBase64(signature) return nil } +func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) { + signature, err := k.Sign(rand.Reader, hashed, hash) + if err != nil { + return nil, err + } + + switch alg { + case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512: + return signature, nil + + case ECDSAP256SHA256, ECDSAP384SHA384: + ecdsaSignature := &struct { + R, S *big.Int + }{} + if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil { + return nil, err + } + + var intlen int + switch alg { + case ECDSAP256SHA256: + intlen = 32 + case ECDSAP384SHA384: + intlen = 48 + } + + signature := intToBytes(ecdsaSignature.R, intlen) + signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...) + return signature, nil + + // There is no defined interface for what a DSA backed crypto.Signer returns + case DSA, DSANSEC3SHA1: + // t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8) + // signature := []byte{byte(t)} + // signature = append(signature, intToBytes(r1, 20)...) + // signature = append(signature, intToBytes(s1, 20)...) + // rr.Signature = signature + } + + return nil, ErrAlg +} + // Verify validates an RRSet with the signature and key. This is only the // cryptographic test, the signature validity period must be checked separately. // This function copies the rdata of some RRs (to lowercase domain names) for the validation to work. @@ -355,6 +425,11 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { // remove the domain name and assume its our } + hash, ok := AlgorithmToHash[rr.Algorithm] + if !ok { + return ErrAlg + } + switch rr.Algorithm { case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, RSAMD5: // TODO(mg): this can be done quicker, ie. cache the pubkey data somewhere?? @@ -362,52 +437,31 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error { if pubkey == nil { return ErrKey } - // Setup the hash as defined for this alg. - var h hash.Hash - var ch crypto.Hash - switch rr.Algorithm { - case RSAMD5: - h = md5.New() - ch = crypto.MD5 - case RSASHA1, RSASHA1NSEC3SHA1: - h = sha1.New() - ch = crypto.SHA1 - case RSASHA256: - h = sha256.New() - ch = crypto.SHA256 - case RSASHA512: - h = sha512.New() - ch = crypto.SHA512 - } - io.WriteString(h, string(signeddata)) - sighash := h.Sum(nil) - return rsa.VerifyPKCS1v15(pubkey, ch, sighash, sigbuf) + + h := hash.New() + h.Write(signeddata) + return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf) + case ECDSAP256SHA256, ECDSAP384SHA384: pubkey := k.publicKeyECDSA() if pubkey == nil { return ErrKey } - var h hash.Hash - switch rr.Algorithm { - case ECDSAP256SHA256: - h = sha256.New() - case ECDSAP384SHA384: - h = sha512.New384() - } - io.WriteString(h, string(signeddata)) - sighash := h.Sum(nil) + // Split sigbuf into the r and s coordinates - r := big.NewInt(0) - r.SetBytes(sigbuf[:len(sigbuf)/2]) - s := big.NewInt(0) - s.SetBytes(sigbuf[len(sigbuf)/2:]) - if ecdsa.Verify(pubkey, sighash, r, s) { + r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2]) + s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:]) + + h := hash.New() + h.Write(signeddata) + if ecdsa.Verify(pubkey, h.Sum(nil), r, s) { return nil } return ErrSig + + default: + return ErrAlg } - // Unknown alg - return ErrAlg } // ValidityPeriod uses RFC1982 serial arithmetic to calculate @@ -603,36 +657,3 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) { } return buf, nil } - -// Map for algorithm names. -var AlgorithmToString = map[uint8]string{ - RSAMD5: "RSAMD5", - DH: "DH", - DSA: "DSA", - RSASHA1: "RSASHA1", - DSANSEC3SHA1: "DSA-NSEC3-SHA1", - RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1", - RSASHA256: "RSASHA256", - RSASHA512: "RSASHA512", - ECCGOST: "ECC-GOST", - ECDSAP256SHA256: "ECDSAP256SHA256", - ECDSAP384SHA384: "ECDSAP384SHA384", - INDIRECT: "INDIRECT", - PRIVATEDNS: "PRIVATEDNS", - PRIVATEOID: "PRIVATEOID", -} - -// Map of algorithm strings. -var StringToAlgorithm = reverseInt8(AlgorithmToString) - -// Map for hash names. -var HashToString = map[uint8]string{ - SHA1: "SHA1", - SHA256: "SHA256", - GOST94: "GOST94", - SHA384: "SHA384", - SHA512: "SHA512", -} - -// Map of hash strings. -var StringToHash = reverseInt8(HashToString) diff --git a/dnssec_keygen.go b/dnssec_keygen.go index 739beebe..229a0793 100644 --- a/dnssec_keygen.go +++ b/dnssec_keygen.go @@ -1,6 +1,7 @@ package dns import ( + "crypto" "crypto/dsa" "crypto/ecdsa" "crypto/elliptic" @@ -15,7 +16,7 @@ import ( // what kind of DNSKEY will be generated. // The ECDSA algorithms imply a fixed keysize, in that case // bits should be set to the size of the algorithm. -func (k *DNSKEY) Generate(bits int) (PrivateKey, error) { +func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) { switch k.Algorithm { case DSA, DSANSEC3SHA1: if bits != 1024 { @@ -52,14 +53,14 @@ func (k *DNSKEY) Generate(bits int) (PrivateKey, error) { return nil, err } k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y) - return (*DSAPrivateKey)(priv), nil + return priv, nil case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1: priv, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { return nil, err } k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N) - return (*RSAPrivateKey)(priv), nil + return priv, nil case ECDSAP256SHA256, ECDSAP384SHA384: var c elliptic.Curve switch k.Algorithm { @@ -73,7 +74,7 @@ func (k *DNSKEY) Generate(bits int) (PrivateKey, error) { return nil, err } k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y) - return (*ECDSAPrivateKey)(priv), nil + return priv, nil default: return nil, ErrAlg } diff --git a/dnssec_keyscan.go b/dnssec_keyscan.go index ac84fbcb..19a78338 100644 --- a/dnssec_keyscan.go +++ b/dnssec_keyscan.go @@ -1,6 +1,7 @@ package dns import ( + "crypto" "crypto/dsa" "crypto/ecdsa" "crypto/rsa" @@ -12,7 +13,7 @@ import ( // NewPrivateKey returns a PrivateKey by parsing the string s. // s should be in the same form of the BIND private key files. -func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) { +func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) { if s[len(s)-1] != '\n' { // We need a closing newline return k.ReadPrivateKey(strings.NewReader(s+"\n"), "") } @@ -23,7 +24,7 @@ func (k *DNSKEY) NewPrivateKey(s string) (PrivateKey, error) { // only used in error reporting. // The public key must be known, because some cryptographic algorithms embed // the public inside the privatekey. -func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) { +func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error) { m, e := parseKey(q, file) if m == nil { return nil, e @@ -50,7 +51,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) { return nil, ErrKey } priv.PublicKey = *pub - return (*DSAPrivateKey)(priv), e + return priv, e case RSAMD5: fallthrough case RSASHA1: @@ -69,7 +70,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) { return nil, ErrKey } priv.PublicKey = *pub - return (*RSAPrivateKey)(priv), e + return priv, e case ECCGOST: return nil, ErrPrivKey case ECDSAP256SHA256: @@ -84,7 +85,7 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (PrivateKey, error) { return nil, ErrKey } priv.PublicKey = *pub - return (*ECDSAPrivateKey)(priv), e + return priv, e default: return nil, ErrPrivKey } diff --git a/dnssec_privkey.go b/dnssec_privkey.go index 0b8f282b..56f3ea93 100644 --- a/dnssec_privkey.go +++ b/dnssec_privkey.go @@ -4,7 +4,6 @@ import ( "crypto" "crypto/dsa" "crypto/ecdsa" - "crypto/rand" "crypto/rsa" "math/big" "strconv" @@ -12,133 +11,75 @@ import ( const format = "Private-key-format: v1.3\n" -// PrivateKey ... TODO(miek) -type PrivateKey interface { - Sign([]byte, uint8) ([]byte, error) - String(uint8) string -} - // PrivateKeyString converts a PrivateKey to a string. This string has the same // format as the private-key-file of BIND9 (Private-key-format: v1.3). -// It needs some info from the key (the algorithm), so its a method of the -// DNSKEY and calls PrivateKey.String(alg). -func (r *DNSKEY) PrivateKeyString(p PrivateKey) string { - return p.String(r.Algorithm) -} +// It needs some info from the key (the algorithm), so its a method of the DNSKEY +// It supports rsa.PrivateKey, ecdsa.PrivateKey and dsa.PrivateKey +func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string { + algorithm := strconv.Itoa(int(r.Algorithm)) + algorithm += " (" + AlgorithmToString[r.Algorithm] + ")" -type RSAPrivateKey rsa.PrivateKey + switch p := p.(type) { + case *rsa.PrivateKey: + modulus := toBase64(p.PublicKey.N.Bytes()) + e := big.NewInt(int64(p.PublicKey.E)) + publicExponent := toBase64(e.Bytes()) + privateExponent := toBase64(p.D.Bytes()) + prime1 := toBase64(p.Primes[0].Bytes()) + prime2 := toBase64(p.Primes[1].Bytes()) + // Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm + // and from: http://code.google.com/p/go/issues/detail?id=987 + one := big.NewInt(1) + p1 := big.NewInt(0).Sub(p.Primes[0], one) + q1 := big.NewInt(0).Sub(p.Primes[1], one) + exp1 := big.NewInt(0).Mod(p.D, p1) + exp2 := big.NewInt(0).Mod(p.D, q1) + coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0]) + + exponent1 := toBase64(exp1.Bytes()) + exponent2 := toBase64(exp2.Bytes()) + coefficient := toBase64(coeff.Bytes()) + + return format + + "Algorithm: " + algorithm + "\n" + + "Modulus: " + modulus + "\n" + + "PublicExponent: " + publicExponent + "\n" + + "PrivateExponent: " + privateExponent + "\n" + + "Prime1: " + prime1 + "\n" + + "Prime2: " + prime2 + "\n" + + "Exponent1: " + exponent1 + "\n" + + "Exponent2: " + exponent2 + "\n" + + "Coefficient: " + coefficient + "\n" + + case *ecdsa.PrivateKey: + var intlen int + switch r.Algorithm { + case ECDSAP256SHA256: + intlen = 32 + case ECDSAP384SHA384: + intlen = 48 + } + private := toBase64(intToBytes(p.D, intlen)) + return format + + "Algorithm: " + algorithm + "\n" + + "PrivateKey: " + private + "\n" + + case *dsa.PrivateKey: + T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8) + prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8)) + subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20)) + base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8)) + priv := toBase64(intToBytes(p.X, 20)) + pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8)) + return format + + "Algorithm: " + algorithm + "\n" + + "Prime(p): " + prime + "\n" + + "Subprime(q): " + subprime + "\n" + + "Base(g): " + base + "\n" + + "Private_value(x): " + priv + "\n" + + "Public_value(y): " + pub + "\n" -func (p *RSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) { - var hash crypto.Hash - switch alg { - case RSASHA1, RSASHA1NSEC3SHA1: - hash = crypto.SHA1 - case RSASHA256: - hash = crypto.SHA256 - case RSASHA512: - hash = crypto.SHA512 default: - return nil, ErrAlg + return "" } - return rsa.SignPKCS1v15(nil, (*rsa.PrivateKey)(p), hash, hashed) -} - -func (p *RSAPrivateKey) String(alg uint8) string { - algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")" - modulus := toBase64(p.PublicKey.N.Bytes()) - e := big.NewInt(int64(p.PublicKey.E)) - publicExponent := toBase64(e.Bytes()) - privateExponent := toBase64(p.D.Bytes()) - prime1 := toBase64(p.Primes[0].Bytes()) - prime2 := toBase64(p.Primes[1].Bytes()) - // Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm - // and from: http://code.google.com/p/go/issues/detail?id=987 - one := big.NewInt(1) - p1 := big.NewInt(0).Sub(p.Primes[0], one) - q1 := big.NewInt(0).Sub(p.Primes[1], one) - exp1 := big.NewInt(0).Mod(p.D, p1) - exp2 := big.NewInt(0).Mod(p.D, q1) - coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0]) - - exponent1 := toBase64(exp1.Bytes()) - exponent2 := toBase64(exp2.Bytes()) - coefficient := toBase64(coeff.Bytes()) - - return format + - "Algorithm: " + algorithm + "\n" + - "Modulus: " + modulus + "\n" + - "PublicExponent: " + publicExponent + "\n" + - "PrivateExponent: " + privateExponent + "\n" + - "Prime1: " + prime1 + "\n" + - "Prime2: " + prime2 + "\n" + - "Exponent1: " + exponent1 + "\n" + - "Exponent2: " + exponent2 + "\n" + - "Coefficient: " + coefficient + "\n" -} - -type ECDSAPrivateKey ecdsa.PrivateKey - -func (p *ECDSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) { - var intlen int - switch alg { - case ECDSAP256SHA256: - intlen = 32 - case ECDSAP384SHA384: - intlen = 48 - default: - return nil, ErrAlg - } - r1, s1, err := ecdsa.Sign(rand.Reader, (*ecdsa.PrivateKey)(p), hashed) - if err != nil { - return nil, err - } - signature := intToBytes(r1, intlen) - signature = append(signature, intToBytes(s1, intlen)...) - return signature, nil -} - -func (p *ECDSAPrivateKey) String(alg uint8) string { - algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")" - var intlen int - switch alg { - case ECDSAP256SHA256: - intlen = 32 - case ECDSAP384SHA384: - intlen = 48 - } - private := toBase64(intToBytes(p.D, intlen)) - return format + - "Algorithm: " + algorithm + "\n" + - "PrivateKey: " + private + "\n" -} - -type DSAPrivateKey dsa.PrivateKey - -func (p *DSAPrivateKey) Sign(hashed []byte, alg uint8) ([]byte, error) { - r1, s1, err := dsa.Sign(rand.Reader, (*dsa.PrivateKey)(p), hashed) - if err != nil { - return nil, err - } - t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8) - signature := []byte{byte(t)} - signature = append(signature, intToBytes(r1, 20)...) - signature = append(signature, intToBytes(s1, 20)...) - return signature, nil -} - -func (p *DSAPrivateKey) String(alg uint8) string { - algorithm := strconv.Itoa(int(alg)) + " (" + AlgorithmToString[alg] + ")" - T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8) - prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8)) - subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20)) - base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8)) - priv := toBase64(intToBytes(p.X, 20)) - pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8)) - return format + - "Algorithm: " + algorithm + "\n" + - "Prime(p): " + prime + "\n" + - "Subprime(q): " + subprime + "\n" + - "Base(g): " + base + "\n" + - "Private_value(x): " + priv + "\n" + - "Public_value(y): " + pub + "\n" } diff --git a/dnssec_test.go b/dnssec_test.go index 0975ed50..839aa386 100644 --- a/dnssec_test.go +++ b/dnssec_test.go @@ -1,6 +1,9 @@ package dns import ( + "crypto" + "crypto/ecdsa" + "crypto/rsa" "reflect" "strings" "testing" @@ -192,7 +195,7 @@ func TestSignVerify(t *testing.T) { sig.Algorithm = RSASHA256 for _, r := range []RR{soa, soa1, srv} { - if sig.Sign(privkey, []RR{r}) != nil { + if sig.Sign(privkey.(*rsa.PrivateKey), []RR{r}) != nil { t.Error("failure to sign the record") continue } @@ -228,7 +231,7 @@ func Test65534(t *testing.T) { sig.KeyTag = key.KeyTag() sig.SignerName = key.Hdr.Name sig.Algorithm = RSASHA256 - if err := sig.Sign(privkey, []RR{t6}); err != nil { + if err := sig.Sign(privkey.(*rsa.PrivateKey), []RR{t6}); err != nil { t.Error(err) t.Error("failure to sign the TYPE65534 record") } @@ -324,7 +327,7 @@ func TestKeyRSA(t *testing.T) { sig.KeyTag = key.KeyTag() sig.SignerName = key.Hdr.Name - if err := sig.Sign(priv, []RR{soa}); err != nil { + if err := sig.Sign(priv.(*rsa.PrivateKey), []RR{soa}); err != nil { t.Error("failed to sign") return } @@ -374,7 +377,7 @@ Activate: 20110302104537` t.Error(err) } switch priv := p.(type) { - case *RSAPrivateKey: + case *rsa.PrivateKey: if 65537 != priv.PublicKey.E { t.Error("exponenent should be 65537") } @@ -403,7 +406,7 @@ Activate: 20110302104537` sig.SignerName = k.Hdr.Name sig.Algorithm = k.Algorithm - sig.Sign(p, []RR{soa}) + sig.Sign(p.(*rsa.PrivateKey), []RR{soa}) if sig.Signature != "D5zsobpQcmMmYsUMLxCVEtgAdCvTu8V/IEeP4EyLBjqPJmjt96bwM9kqihsccofA5LIJ7DN91qkCORjWSTwNhzCv7bMyr2o5vBZElrlpnRzlvsFIoAZCD9xg6ZY7ZyzUJmU6IcTwG4v3xEYajcpbJJiyaw/RqR90MuRdKPiBzSo=" { t.Errorf("signature is not correct: %v", sig) } @@ -443,7 +446,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR` sig.SignerName = eckey.(*DNSKEY).Hdr.Name sig.Algorithm = eckey.(*DNSKEY).Algorithm - if sig.Sign(privkey, []RR{a}) != nil { + if sig.Sign(privkey.(*ecdsa.PrivateKey), []RR{a}) != nil { t.Fatal("failure to sign the record") } @@ -491,7 +494,7 @@ func TestSignVerifyECDSA2(t *testing.T) { sig.SignerName = key.Hdr.Name sig.Algorithm = ECDSAP256SHA256 - if sig.Sign(privkey, []RR{srv}) != nil { + if sig.Sign(privkey.(*ecdsa.PrivateKey), []RR{srv}) != nil { t.Fatal("failure to sign the record") } @@ -564,7 +567,7 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=` } ourRRSIG.Expiration, _ = StringToTime("20100909100439") ourRRSIG.Inception, _ = StringToTime("20100812100439") - err = ourRRSIG.Sign(priv, []RR{rrA}) + err = ourRRSIG.Sign(priv.(*ecdsa.PrivateKey), []RR{rrA}) if err != nil { t.Fatal(err) } @@ -640,7 +643,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR` } ourRRSIG.Expiration, _ = StringToTime("20100909102025") ourRRSIG.Inception, _ = StringToTime("20100812102025") - err = ourRRSIG.Sign(priv, []RR{rrA}) + err = ourRRSIG.Sign(priv.(*ecdsa.PrivateKey), []RR{rrA}) if err != nil { t.Fatal(err) } @@ -709,7 +712,7 @@ func TestInvalidRRSet(t *testing.T) { } // Sign the good record set and then make sure verification fails on the bad record set - if err := signature.Sign(privatekey, goodRecords); err != nil { + if err := signature.Sign(privatekey.(crypto.Signer), goodRecords); err != nil { t.Fatal("Signing good records failed") } diff --git a/parse_test.go b/parse_test.go index 36a586d2..c2579bcc 100644 --- a/parse_test.go +++ b/parse_test.go @@ -1237,8 +1237,8 @@ func TestNewPrivateKey(t *testing.T) { } switch newPrivKey := newPrivKey.(type) { - case *RSAPrivateKey: - (*rsa.PrivateKey)(newPrivKey).Precompute() + case *rsa.PrivateKey: + newPrivKey.Precompute() } if !reflect.DeepEqual(privkey, newPrivKey) { diff --git a/sig0.go b/sig0.go index 55d1a4ed..0fccddbc 100644 --- a/sig0.go +++ b/sig0.go @@ -13,7 +13,7 @@ import ( // Sign signs a dns.Msg. It fills the signature with the appropriate data. // The SIG record should have the SignerName, KeyTag, Algorithm, Inception // and Expiration set. -func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) { +func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) { if k == nil { return nil, ErrPrivKey } @@ -41,31 +41,26 @@ func (rr *SIG) Sign(k PrivateKey, m *Msg) ([]byte, error) { return nil, err } buf = buf[:off:cap(buf)] - var hash crypto.Hash - switch rr.Algorithm { - case DSA, RSASHA1: - hash = crypto.SHA1 - case RSASHA256, ECDSAP256SHA256: - hash = crypto.SHA256 - case ECDSAP384SHA384: - hash = crypto.SHA384 - case RSASHA512: - hash = crypto.SHA512 - default: + + hash, ok := AlgorithmToHash[rr.Algorithm] + if !ok { return nil, ErrAlg } + hasher := hash.New() // Write SIG rdata hasher.Write(buf[len(mbuf)+1+2+2+4+2:]) // Write message hasher.Write(buf[:len(mbuf)]) - hashed := hasher.Sum(nil) - sig, err := k.Sign(hashed, rr.Algorithm) + signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm) if err != nil { return nil, err } - rr.Signature = toBase64(sig) + + rr.Signature = toBase64(signature) + sig := string(signature) + buf = append(buf, sig...) if len(buf) > int(^uint16(0)) { return nil, ErrBuf diff --git a/sig0_test.go b/sig0_test.go index cdd57ab8..c13adf39 100644 --- a/sig0_test.go +++ b/sig0_test.go @@ -1,6 +1,7 @@ package dns import ( + "crypto" "testing" "time" ) @@ -11,7 +12,7 @@ func TestSIG0(t *testing.T) { } m := new(Msg) m.SetQuestion("example.org.", TypeSOA) - for _, alg := range []uint8{DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256, RSASHA512} { + for _, alg := range []uint8{ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256, RSASHA512} { algstr := AlgorithmToString[alg] keyrr := new(KEY) keyrr.Hdr.Name = algstr + "." @@ -40,7 +41,7 @@ func TestSIG0(t *testing.T) { sigrr.Inception = now - 300 sigrr.KeyTag = keyrr.KeyTag() sigrr.SignerName = keyrr.Hdr.Name - mb, err := sigrr.Sign(pk, m) + mb, err := sigrr.Sign(pk.(crypto.Signer), m) if err != nil { t.Errorf("Failed to sign message using ā€œ%sā€: %v", algstr, err) continue @@ -79,7 +80,7 @@ func TestSIG0(t *testing.T) { } sigrr.Expiration = 2 sigrr.Inception = 1 - mb, _ = sigrr.Sign(pk, m) + mb, _ = sigrr.Sign(pk.(crypto.Signer), m) if err := sigrr.Verify(keyrr, mb); err == nil { t.Errorf("Verify succeeded on an expired message using ā€œ%sā€", algstr) continue