From: Michael Munday Date: Wed, 16 Oct 2019 21:38:40 +0000 (+0100) Subject: [release-branch.go1.13] crypto/ecdsa: remove s390x assembly X-Git-Tag: go1.13.3~5 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=4cb22ee8120ddd9cd8a9ef88ae2a142c5d2f8432;p=gostls13.git [release-branch.go1.13] crypto/ecdsa: remove s390x assembly This is a revert of CL 174437 and equivalent to CL 201360. The size of the params block passed into the KDSA instruction is incorrect and this appears to result in out-of-bounds writes that cause a panic in the crypto/x509 tests when run on a machine that supports KDSA. Remove this assembly for now. We can revisit the use of the KDSA instruction in a future release. Fixes #34928. Change-Id: I7ad2fe9714b47ad04abc25f18aa235b9d2aef062 Reviewed-on: https://go-review.googlesource.com/c/go/+/201361 Run-TryBot: Michael Munday Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index ddc3b35ba3..cc1134f74f 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -189,21 +189,14 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err // See [NSA] 3.4.1 c := priv.PublicKey.Curve - e := hashToInt(hash, c) - r, s, err = sign(priv, &csprng, c, e) - return -} - -func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, e *big.Int) (r, s *big.Int, err error) { N := c.Params().N if N.Sign() == 0 { return nil, nil, errZeroParam } - var k, kInv *big.Int for { for { - k, err = randFieldElement(c, *csprng) + k, err = randFieldElement(c, csprng) if err != nil { r = nil return @@ -221,6 +214,8 @@ func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve break } } + + e := hashToInt(hash, c) s = new(big.Int).Mul(priv.D, r) s.Add(s, e) s.Mul(s, kInv) @@ -229,6 +224,7 @@ func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve break } } + return } @@ -246,12 +242,8 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { return false } e := hashToInt(hash, c) - return verify(pub, c, e, r, s) -} -func verifyGeneric(pub *PublicKey, c elliptic.Curve, e, r, s *big.Int) bool { var w *big.Int - N := c.Params().N if in, ok := c.(invertible); ok { w = in.Inverse(s) } else { diff --git a/src/crypto/ecdsa/ecdsa_noasm.go b/src/crypto/ecdsa/ecdsa_noasm.go deleted file mode 100644 index 2dfdb866d6..0000000000 --- a/src/crypto/ecdsa/ecdsa_noasm.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019 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, e *big.Int) (r, s *big.Int, err error) { - r, s, err = signGeneric(priv, csprng, c, e) - return -} - -func verify(pub *PublicKey, c elliptic.Curve, e, r, s *big.Int) bool { - return verifyGeneric(pub, c, e, r, s) -} diff --git a/src/crypto/ecdsa/ecdsa_s390x.go b/src/crypto/ecdsa/ecdsa_s390x.go deleted file mode 100644 index f07c3bf50c..0000000000 --- a/src/crypto/ecdsa/ecdsa_s390x.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2019 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,!gccgo - -package ecdsa - -import ( - "crypto/cipher" - "crypto/elliptic" - "internal/cpu" - "math/big" -) - -// s390x accelerated signatures -//go:noescape -func kdsaSig(fc uint64, block *[1720]byte) (errn uint64) - -type signverify int - -const ( - signing signverify = iota - verifying -) - -// bufferOffsets represents the offset of a particular parameter in -// the buffer passed to the KDSA instruction. -type bufferOffsets struct { - baseSize int - hashSize int - offsetHash int - offsetKey1 int - offsetRNorKey2 int - offsetR int - offsetS int - functionCode uint64 -} - -func canUseKDSA(sv signverify, c elliptic.Curve, bo *bufferOffsets) bool { - if !cpu.S390X.HasECDSA { - return false - } - - switch c.Params().Name { - case "P-256": - bo.baseSize = 32 - bo.hashSize = 32 - bo.offsetHash = 64 - bo.offsetKey1 = 96 - bo.offsetRNorKey2 = 128 - bo.offsetR = 0 - bo.offsetS = 32 - if sv == signing { - bo.functionCode = 137 - } else { - bo.functionCode = 1 - } - return true - case "P-384": - bo.baseSize = 48 - bo.hashSize = 48 - bo.offsetHash = 96 - bo.offsetKey1 = 144 - bo.offsetRNorKey2 = 192 - bo.offsetR = 0 - bo.offsetS = 48 - if sv == signing { - bo.functionCode = 138 - } else { - bo.functionCode = 2 - } - return true - case "P-521": - bo.baseSize = 66 - bo.hashSize = 80 - bo.offsetHash = 160 - bo.offsetKey1 = 254 - bo.offsetRNorKey2 = 334 - bo.offsetR = 14 - bo.offsetS = 94 - if sv == signing { - bo.functionCode = 139 - } else { - bo.functionCode = 3 - } - return true - } - return false -} - -// 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, e *big.Int) (r, s *big.Int, err error) { - var bo bufferOffsets - if canUseKDSA(signing, c, &bo) && e.Sign() != 0 { - var buffer [1720]byte - for { - var k *big.Int - k, err = randFieldElement(c, csprng) - if err != nil { - return nil, nil, err - } - zeroExtendAndCopy(buffer[bo.offsetHash:], e.Bytes(), bo.hashSize) - zeroExtendAndCopy(buffer[bo.offsetKey1:], priv.D.Bytes(), bo.baseSize) - zeroExtendAndCopy(buffer[bo.offsetRNorKey2:], k.Bytes(), bo.baseSize) - errn := kdsaSig(bo.functionCode, &buffer) - if errn == 2 { - return nil, nil, errZeroParam - } - if errn == 0 { // success == 0 means successful signing - r = new(big.Int) - r.SetBytes(buffer[bo.offsetR : bo.offsetR+bo.baseSize]) - s = new(big.Int) - s.SetBytes(buffer[bo.offsetS : bo.offsetS+bo.baseSize]) - return - } - //at this point, it must be that errn == 1: retry - } - } - r, s, err = signGeneric(priv, csprng, c, e) - return -} - -func verify(pub *PublicKey, c elliptic.Curve, e, r, s *big.Int) bool { - var bo bufferOffsets - if canUseKDSA(verifying, c, &bo) && e.Sign() != 0 { - var buffer [1720]byte - zeroExtendAndCopy(buffer[bo.offsetR:], r.Bytes(), bo.baseSize) - zeroExtendAndCopy(buffer[bo.offsetS:], s.Bytes(), bo.baseSize) - zeroExtendAndCopy(buffer[bo.offsetHash:], e.Bytes(), bo.hashSize) - zeroExtendAndCopy(buffer[bo.offsetKey1:], pub.X.Bytes(), bo.baseSize) - zeroExtendAndCopy(buffer[bo.offsetRNorKey2:], pub.Y.Bytes(), bo.baseSize) - errn := kdsaSig(bo.functionCode, &buffer) - return errn == 0 - } - return verifyGeneric(pub, c, e, r, s) -} diff --git a/src/crypto/ecdsa/ecdsa_s390x.s b/src/crypto/ecdsa/ecdsa_s390x.s deleted file mode 100644 index 6ee00ce79c..0000000000 --- a/src/crypto/ecdsa/ecdsa_s390x.s +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2019 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. - -#include "textflag.h" - -// func kdsaSig(fc uint64, block *[1720]byte) (errn uint64) -TEXT ·kdsaSig(SB), NOSPLIT|NOFRAME, $0-24 - MOVD fc+0(FP), R0 // function code - MOVD block+8(FP), R1 // address parameter block - -loop: - WORD $0xB93A0008 // compute digital signature authentication - BVS loop // branch back if interrupted - BEQ success // signature creation successful - BGT retry // signing unsuccessful, but retry with new CSPRN - -error: - MOVD $2, R2 // fallthrough indicates fatal error - MOVD R2, errn+16(FP) // return 2 - sign/verify abort - RET - -retry: - MOVD $1, R2 - MOVD R2, errn+16(FP) // return 1 - sign/verify was unsuccessful -- if sign, retry with new RN - RET - -success: - MOVD $0, R2 - MOVD R2, errn+16(FP) // return 0 - sign/verify was successful - RET diff --git a/src/crypto/ecdsa/ecdsa_s390x_test.go b/src/crypto/ecdsa/ecdsa_s390x_test.go deleted file mode 100644 index 80babc9cb4..0000000000 --- a/src/crypto/ecdsa/ecdsa_s390x_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 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,!gccgo - -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) - } -}