diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-07-27 22:27:54 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-08-01 11:21:40 -0700 |
commit | f75af8c1464e948b5e166cf5ab09ebf0d82fc253 (patch) | |
tree | 3ba3299859b504bdeb477727471216bd094a0191 /libgo/go/crypto/ecdsa | |
parent | 75a23e59031fe673fc3b2e60fd1fe5f4c70ecb85 (diff) | |
download | gcc-f75af8c1464e948b5e166cf5ab09ebf0d82fc253.zip gcc-f75af8c1464e948b5e166cf5ab09ebf0d82fc253.tar.gz gcc-f75af8c1464e948b5e166cf5ab09ebf0d82fc253.tar.bz2 |
libgo: update to go1.15rc1
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/245157
Diffstat (limited to 'libgo/go/crypto/ecdsa')
-rw-r--r-- | libgo/go/crypto/ecdsa/ecdsa.go | 88 | ||||
-rw-r--r-- | libgo/go/crypto/ecdsa/ecdsa_noasm.go | 21 | ||||
-rw-r--r-- | libgo/go/crypto/ecdsa/ecdsa_s390x.go | 164 | ||||
-rw-r--r-- | libgo/go/crypto/ecdsa/ecdsa_s390x_test.go | 34 | ||||
-rw-r--r-- | libgo/go/crypto/ecdsa/ecdsa_test.go | 30 | ||||
-rw-r--r-- | libgo/go/crypto/ecdsa/equal_test.go | 75 | ||||
-rw-r--r-- | libgo/go/crypto/ecdsa/example_test.go | 6 |
7 files changed, 406 insertions, 12 deletions
diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go index 65911e7..ccce873 100644 --- a/libgo/go/crypto/ecdsa/ecdsa.go +++ b/libgo/go/crypto/ecdsa/ecdsa.go @@ -33,10 +33,12 @@ import ( "crypto/elliptic" "crypto/internal/randutil" "crypto/sha512" - "encoding/asn1" "errors" "io" "math/big" + + "golang.org/x/crypto/cryptobyte" + "golang.org/x/crypto/cryptobyte/asn1" ) // A invertible implements fast inverse mod Curve.Params().N @@ -60,21 +62,49 @@ type PublicKey struct { X, Y *big.Int } +// Any methods implemented on PublicKey might need to also be implemented on +// PrivateKey, as the latter embeds the former and will expose its methods. + +// Equal reports whether pub and x have the same value. +// +// Two keys are only considered to have the same value if they have the same Curve value. +// Note that for example elliptic.P256() and elliptic.P256().Params() are different +// values, as the latter is a generic not constant time implementation. +func (pub *PublicKey) Equal(x crypto.PublicKey) bool { + xx, ok := x.(*PublicKey) + if !ok { + return false + } + return pub.X.Cmp(xx.X) == 0 && pub.Y.Cmp(xx.Y) == 0 && + // Standard library Curve implementations are singletons, so this check + // will work for those. Other Curves might be equivalent even if not + // singletons, but there is no definitive way to check for that, and + // better to err on the side of safety. + pub.Curve == xx.Curve +} + // PrivateKey represents an ECDSA private key. type PrivateKey struct { PublicKey D *big.Int } -type ecdsaSignature struct { - R, S *big.Int -} - // Public returns the public key corresponding to priv. func (priv *PrivateKey) Public() crypto.PublicKey { return &priv.PublicKey } +// Equal reports whether priv and x have the same value. +// +// See PublicKey.Equal for details on how Curve is compared. +func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool { + xx, ok := x.(*PrivateKey) + if !ok { + return false + } + return priv.PublicKey.Equal(&xx.PublicKey) && priv.D.Cmp(xx.D) == 0 +} + // Sign signs digest with priv, reading randomness from rand. The opts argument // is not currently used but, in keeping with the crypto.Signer interface, // should be the hash function used to digest the message. @@ -88,7 +118,12 @@ func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOp return nil, err } - return asn1.Marshal(ecdsaSignature{r, s}) + var b cryptobyte.Builder + b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { + b.AddASN1BigInt(r) + b.AddASN1BigInt(s) + }) + return b.Bytes() } var one = new(big.Int).SetInt64(1) @@ -159,7 +194,7 @@ var errZeroParam = errors.New("zero parameter") // Sign signs a hash (which should be the result of hashing a larger message) // using the private key, priv. If the hash is longer than the bit-length of the -// private key's curve order, the hash will be truncated to that length. It +// private key's curve order, the hash will be truncated to that length. It // returns the signature as a pair of integers. The security of the private key // depends on the entropy of rand. func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { @@ -199,6 +234,10 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err // See [NSA] 3.4.1 c := priv.PublicKey.Curve + return sign(priv, &csprng, c, hash) +} + +func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) { N := c.Params().N if N.Sign() == 0 { return nil, nil, errZeroParam @@ -206,7 +245,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err var k, kInv *big.Int for { for { - k, err = randFieldElement(c, csprng) + k, err = randFieldElement(c, *csprng) if err != nil { r = nil return @@ -238,6 +277,15 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err return } +// SignASN1 signs a hash (which should be the result of hashing a larger message) +// using the private key, priv. If the hash is longer than the bit-length of the +// private key's curve order, the hash will be truncated to that length. It +// returns the ASN.1 encoded signature. The security of the private key +// depends on the entropy of rand. +func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) { + return priv.Sign(rand, hash, nil) +} + // Verify verifies the signature in r, s of hash using the public key, pub. Its // return value records whether the signature is valid. func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { @@ -251,9 +299,13 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 { return false } - e := hashToInt(hash, c) + return verify(pub, c, hash, r, s) +} +func verifyGeneric(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool { + e := hashToInt(hash, c) var w *big.Int + N := c.Params().N if in, ok := c.(invertible); ok { w = in.Inverse(s) } else { @@ -282,6 +334,24 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { return x.Cmp(r) == 0 } +// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the +// public key, pub. Its return value records whether the signature is valid. +func VerifyASN1(pub *PublicKey, hash, sig []byte) bool { + var ( + r, s = &big.Int{}, &big.Int{} + inner cryptobyte.String + ) + input := cryptobyte.String(sig) + if !input.ReadASN1(&inner, asn1.SEQUENCE) || + !input.Empty() || + !inner.ReadASN1Integer(r) || + !inner.ReadASN1Integer(s) || + !inner.Empty() { + return false + } + return Verify(pub, hash, r, s) +} + type zr struct { io.Reader } diff --git a/libgo/go/crypto/ecdsa/ecdsa_noasm.go b/libgo/go/crypto/ecdsa/ecdsa_noasm.go new file mode 100644 index 0000000..b7e7317 --- /dev/null +++ b/libgo/go/crypto/ecdsa/ecdsa_noasm.go @@ -0,0 +1,21 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// -build !s390x + +package ecdsa + +import ( + "crypto/cipher" + "crypto/elliptic" + "math/big" +) + +func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) { + return signGeneric(priv, csprng, c, hash) +} + +func verify(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool { + return verifyGeneric(pub, c, hash, r, s) +} diff --git a/libgo/go/crypto/ecdsa/ecdsa_s390x.go b/libgo/go/crypto/ecdsa/ecdsa_s390x.go new file mode 100644 index 0000000..dcbbef3 --- /dev/null +++ b/libgo/go/crypto/ecdsa/ecdsa_s390x.go @@ -0,0 +1,164 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore_for_gccgo + +package ecdsa + +import ( + "crypto/cipher" + "crypto/elliptic" + "internal/cpu" + "math/big" +) + +// kdsa invokes the "compute digital signature authentication" +// instruction with the given function code and 4096 byte +// parameter block. +// +// The return value corresponds to the condition code set by the +// instruction. Interrupted invocations are handled by the +// function. +//go:noescape +func kdsa(fc uint64, params *[4096]byte) (errn uint64) + +// canUseKDSA checks if KDSA instruction is available, and if it is, it checks +// the name of the curve to see if it matches the curves supported(P-256, P-384, P-521). +// Then, based on the curve name, a function code and a block size will be assigned. +// If KDSA instruction is not available or if the curve is not supported, canUseKDSA +// will set ok to false. +func canUseKDSA(c elliptic.Curve) (functionCode uint64, blockSize int, ok bool) { + if !cpu.S390X.HasECDSA { + return 0, 0, false + } + switch c.Params().Name { + case "P-256": + return 1, 32, true + case "P-384": + return 2, 48, true + case "P-521": + return 3, 80, true + } + return 0, 0, false // A mismatch +} + +// zeroExtendAndCopy pads src with leading zeros until it has the size given. +// It then copies the padded src into the dst. Bytes beyond size in dst are +// not modified. +func zeroExtendAndCopy(dst, src []byte, size int) { + nz := size - len(src) + if nz < 0 { + panic("src is too long") + } + // the compiler should replace this loop with a memclr call + z := dst[:nz] + for i := range z { + z[i] = 0 + } + copy(dst[nz:size], src[:size-nz]) + return +} + +func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) { + if functionCode, blockSize, ok := canUseKDSA(c); ok { + e := hashToInt(hash, c) + for { + var k *big.Int + k, err = randFieldElement(c, *csprng) + if err != nil { + return nil, nil, err + } + + // The parameter block looks like the following for sign. + // +---------------------+ + // | Signature(R) | + // +---------------------+ + // | Signature(S) | + // +---------------------+ + // | Hashed Message | + // +---------------------+ + // | Private Key | + // +---------------------+ + // | Random Number | + // +---------------------+ + // | | + // | ... | + // | | + // +---------------------+ + // The common components(signatureR, signatureS, hashedMessage, privateKey and + // random number) each takes block size of bytes. The block size is different for + // different curves and is set by canUseKDSA function. + var params [4096]byte + + startingOffset := 2 * blockSize // Set the starting location for copying + // Copy content into the parameter block. In the sign case, + // we copy hashed message, private key and random number into + // the parameter block. Since those are consecutive components in the parameter + // block, we use a for loop here. + for i, v := range []*big.Int{e, priv.D, k} { + startPosition := startingOffset + i*blockSize + endPosition := startPosition + blockSize + zeroExtendAndCopy(params[startPosition:endPosition], v.Bytes(), blockSize) + } + + // Convert verify function code into a sign function code by adding 8. + // We also need to set the 'deterministic' bit in the function code, by + // adding 128, in order to stop the instruction using its own random number + // generator in addition to the random number we supply. + switch kdsa(functionCode+136, ¶ms) { + case 0: // success + r = new(big.Int) + r.SetBytes(params[:blockSize]) + s = new(big.Int) + s.SetBytes(params[blockSize : 2*blockSize]) + return + case 1: // error + return nil, nil, errZeroParam + case 2: // retry + continue + } + panic("unreachable") + } + } + return signGeneric(priv, csprng, c, hash) +} + +func verify(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool { + if functionCode, blockSize, ok := canUseKDSA(c); ok { + e := hashToInt(hash, c) + // The parameter block looks like the following for verify: + // +---------------------+ + // | Signature(R) | + // +---------------------+ + // | Signature(S) | + // +---------------------+ + // | Hashed Message | + // +---------------------+ + // | Public Key X | + // +---------------------+ + // | Public Key Y | + // +---------------------+ + // | | + // | ... | + // | | + // +---------------------+ + // The common components(signatureR, signatureS, hashed message, public key X, + // and public key Y) each takes block size of bytes. The block size is different for + // different curves and is set by canUseKDSA function. + var params [4096]byte + + // Copy content into the parameter block. In the verify case, + // we copy signature (r), signature(s), hashed message, public key x component, + // and public key y component into the parameter block. + // Since those are consecutive components in the parameter block, we use a for loop here. + for i, v := range []*big.Int{r, s, e, pub.X, pub.Y} { + startPosition := i * blockSize + endPosition := startPosition + blockSize + zeroExtendAndCopy(params[startPosition:endPosition], v.Bytes(), blockSize) + } + + return kdsa(functionCode, ¶ms) == 0 + } + return verifyGeneric(pub, c, hash, r, s) +} diff --git a/libgo/go/crypto/ecdsa/ecdsa_s390x_test.go b/libgo/go/crypto/ecdsa/ecdsa_s390x_test.go new file mode 100644 index 0000000..4fc6dfb --- /dev/null +++ b/libgo/go/crypto/ecdsa/ecdsa_s390x_test.go @@ -0,0 +1,34 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore_for_gccgo +// +build s390x + +package ecdsa + +import ( + "crypto/elliptic" + "testing" +) + +func TestNoAsm(t *testing.T) { + curves := [...]elliptic.Curve{ + elliptic.P256(), + elliptic.P384(), + elliptic.P521(), + } + + for _, curve := range curves { + // override the name of the curve to stop the assembly path being taken + params := *curve.Params() + name := params.Name + params.Name = name + "_GENERIC_OVERRIDE" + + testKeyGeneration(t, ¶ms, name) + testSignAndVerify(t, ¶ms, name) + testNonceSafety(t, ¶ms, name) + testINDCCA(t, ¶ms, name) + testNegativeInputs(t, ¶ms, name) + } +} diff --git a/libgo/go/crypto/ecdsa/ecdsa_test.go b/libgo/go/crypto/ecdsa/ecdsa_test.go index 6284e06..0c1ff6d 100644 --- a/libgo/go/crypto/ecdsa/ecdsa_test.go +++ b/libgo/go/crypto/ecdsa/ecdsa_test.go @@ -131,6 +131,36 @@ func TestSignAndVerify(t *testing.T) { testSignAndVerify(t, elliptic.P521(), "p521") } +func testSignAndVerifyASN1(t *testing.T, c elliptic.Curve, tag string) { + priv, _ := GenerateKey(c, rand.Reader) + + hashed := []byte("testing") + sig, err := SignASN1(rand.Reader, priv, hashed) + if err != nil { + t.Errorf("%s: error signing: %s", tag, err) + return + } + + if !VerifyASN1(&priv.PublicKey, hashed, sig) { + t.Errorf("%s: VerifyASN1 failed", tag) + } + + hashed[0] ^= 0xff + if VerifyASN1(&priv.PublicKey, hashed, sig) { + t.Errorf("%s: VerifyASN1 always works!", tag) + } +} + +func TestSignAndVerifyASN1(t *testing.T) { + testSignAndVerifyASN1(t, elliptic.P224(), "p224") + if testing.Short() { + return + } + testSignAndVerifyASN1(t, elliptic.P256(), "p256") + testSignAndVerifyASN1(t, elliptic.P384(), "p384") + testSignAndVerifyASN1(t, elliptic.P521(), "p521") +} + func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) { priv, _ := GenerateKey(c, rand.Reader) diff --git a/libgo/go/crypto/ecdsa/equal_test.go b/libgo/go/crypto/ecdsa/equal_test.go new file mode 100644 index 0000000..53ac850 --- /dev/null +++ b/libgo/go/crypto/ecdsa/equal_test.go @@ -0,0 +1,75 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ecdsa_test + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "testing" +) + +func testEqual(t *testing.T, c elliptic.Curve) { + private, _ := ecdsa.GenerateKey(c, rand.Reader) + public := &private.PublicKey + + if !public.Equal(public) { + t.Errorf("public key is not equal to itself: %v", public) + } + if !public.Equal(crypto.Signer(private).Public().(*ecdsa.PublicKey)) { + t.Errorf("private.Public() is not Equal to public: %q", public) + } + if !private.Equal(private) { + t.Errorf("private key is not equal to itself: %v", private) + } + + enc, err := x509.MarshalPKCS8PrivateKey(private) + if err != nil { + t.Fatal(err) + } + decoded, err := x509.ParsePKCS8PrivateKey(enc) + if err != nil { + t.Fatal(err) + } + if !public.Equal(decoded.(crypto.Signer).Public()) { + t.Errorf("public key is not equal to itself after decoding: %v", public) + } + if !private.Equal(decoded) { + t.Errorf("private key is not equal to itself after decoding: %v", private) + } + + other, _ := ecdsa.GenerateKey(c, rand.Reader) + if public.Equal(other.Public()) { + t.Errorf("different public keys are Equal") + } + if private.Equal(other) { + t.Errorf("different private keys are Equal") + } + + // Ensure that keys with the same coordinates but on different curves + // aren't considered Equal. + differentCurve := &ecdsa.PublicKey{} + *differentCurve = *public // make a copy of the public key + if differentCurve.Curve == elliptic.P256() { + differentCurve.Curve = elliptic.P224() + } else { + differentCurve.Curve = elliptic.P256() + } + if public.Equal(differentCurve) { + t.Errorf("public keys with different curves are Equal") + } +} + +func TestEqual(t *testing.T) { + t.Run("P224", func(t *testing.T) { testEqual(t, elliptic.P224()) }) + if testing.Short() { + return + } + t.Run("P256", func(t *testing.T) { testEqual(t, elliptic.P256()) }) + t.Run("P384", func(t *testing.T) { testEqual(t, elliptic.P384()) }) + t.Run("P521", func(t *testing.T) { testEqual(t, elliptic.P521()) }) +} diff --git a/libgo/go/crypto/ecdsa/example_test.go b/libgo/go/crypto/ecdsa/example_test.go index 7c7fb1b..a9e7a03 100644 --- a/libgo/go/crypto/ecdsa/example_test.go +++ b/libgo/go/crypto/ecdsa/example_test.go @@ -23,12 +23,12 @@ func Example() { msg := "hello, world" hash := sha256.Sum256([]byte(msg)) - r, s, err := ecdsa.Sign(rand.Reader, privateKey, hash[:]) + sig, err := ecdsa.SignASN1(rand.Reader, privateKey, hash[:]) if err != nil { panic(err) } - fmt.Printf("signature: (0x%x, 0x%x)\n", r, s) + fmt.Printf("signature: %x\n", sig) - valid := ecdsa.Verify(&privateKey.PublicKey, hash[:], r, s) + valid := ecdsa.VerifyASN1(&privateKey.PublicKey, hash[:], sig) fmt.Println("signature verified:", valid) } |