Skip to content

Commit c4f356d

Browse files
FiloSottilegopherbot
authored andcommitted
crypto/ecdsa: fix s390x assembly with P-521
I had incorrectly assumed that the blocksize was always the same as the curve field size. This is true of P-256 and P-384, but not P-521. Fixes #70660 Fixes #70771 Change-Id: Idb6b510fcd3dd42d9b1e6cf42c1bb92e0ce8bd07 Reviewed-on: https://go-review.googlesource.com/c/go/+/636015 Run-TryBot: Filippo Valsorda <[email protected]> Reviewed-by: Carlos Amedee <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Filippo Valsorda <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]>
1 parent 08725f9 commit c4f356d

File tree

2 files changed

+44
-13
lines changed

2 files changed

+44
-13
lines changed

src/crypto/internal/fips140/ecdsa/ecdsa.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121

2222
type PrivateKey struct {
2323
pub PublicKey
24-
d []byte // bigmod.(*Nat).Bytes output (fixed length)
24+
d []byte // bigmod.(*Nat).Bytes output (same length as the curve order)
2525
}
2626

2727
func (priv *PrivateKey) Bytes() []byte {
@@ -262,7 +262,7 @@ func randomPoint[P Point[P]](c *Curve[P], generate func([]byte) error) (k *bigmo
262262
var testingOnlyRejectionSamplingLooped func()
263263

264264
// Signature is an ECDSA signature, where r and s are represented as big-endian
265-
// fixed-length byte slices.
265+
// byte slices of the same length as the curve order.
266266
type Signature struct {
267267
R, S []byte
268268
}

src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go

+42-11
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,34 @@ func canUseKDSA(c curveID) (functionCode uint64, blockSize int, ok bool) {
4747
case p384:
4848
return 2, 48, true
4949
case p521:
50+
// Note that the block size doesn't match the field size for P-521.
5051
return 3, 80, true
5152
}
5253
return 0, 0, false // A mismatch
5354
}
5455

55-
func hashToBytes[P Point[P]](c *Curve[P], dst, hash []byte) {
56+
func hashToBytes[P Point[P]](c *Curve[P], hash []byte) []byte {
5657
e := bigmod.NewNat()
5758
hashToNat(c, e, hash)
58-
copy(dst, e.Bytes(c.N))
59+
return e.Bytes(c.N)
60+
}
61+
62+
func appendBlock(p []byte, blocksize int, b []byte) []byte {
63+
if len(b) > blocksize {
64+
panic("ecdsa: internal error: appendBlock input larger than block")
65+
}
66+
padding := blocksize - len(b)
67+
p = append(p, make([]byte, padding)...)
68+
return append(p, b...)
69+
}
70+
71+
func trimBlock(p []byte, size int) ([]byte, error) {
72+
for _, b := range p[:len(p)-size] {
73+
if b != 0 {
74+
return nil, errors.New("ecdsa: internal error: KDSA produced invalid signature")
75+
}
76+
}
77+
return p[len(p)-size:], nil
5978
}
6079

6180
func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte) (*Signature, error) {
@@ -95,17 +114,27 @@ func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte
95114

96115
// Copy content into the parameter block. In the sign case,
97116
// we copy hashed message, private key and random number into
98-
// the parameter block.
99-
hashToBytes(c, params[2*blockSize:3*blockSize], hash)
100-
copy(params[3*blockSize+blockSize-len(priv.d):], priv.d)
101-
copy(params[4*blockSize:5*blockSize], k.Bytes(c.N))
117+
// the parameter block. We skip the signature slots.
118+
p := params[:2*blockSize]
119+
p = appendBlock(p, blockSize, hashToBytes(c, hash))
120+
p = appendBlock(p, blockSize, priv.d)
121+
p = appendBlock(p, blockSize, k.Bytes(c.N))
102122
// Convert verify function code into a sign function code by adding 8.
103123
// We also need to set the 'deterministic' bit in the function code, by
104124
// adding 128, in order to stop the instruction using its own random number
105125
// generator in addition to the random number we supply.
106126
switch kdsa(functionCode+136, &params) {
107127
case 0: // success
108-
return &Signature{R: params[:blockSize], S: params[blockSize : 2*blockSize]}, nil
128+
elementSize := (c.N.BitLen() + 7) / 8
129+
r, err := trimBlock(params[:blockSize], elementSize)
130+
if err != nil {
131+
return nil, err
132+
}
133+
s, err := trimBlock(params[blockSize:2*blockSize], elementSize)
134+
if err != nil {
135+
return nil, err
136+
}
137+
return &Signature{R: r, S: s}, nil
109138
case 1: // error
110139
return nil, errors.New("zero parameter")
111140
case 2: // retry
@@ -149,10 +178,12 @@ func verify[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature
149178
// Copy content into the parameter block. In the verify case,
150179
// we copy signature (r), signature(s), hashed message, public key x component,
151180
// and public key y component into the parameter block.
152-
copy(params[0*blockSize+blockSize-len(r):], r)
153-
copy(params[1*blockSize+blockSize-len(s):], s)
154-
hashToBytes(c, params[2*blockSize:3*blockSize], hash)
155-
copy(params[3*blockSize:5*blockSize], pub.q[1:]) // strip 0x04 prefix
181+
p := params[:0]
182+
p = appendBlock(p, blockSize, r)
183+
p = appendBlock(p, blockSize, s)
184+
p = appendBlock(p, blockSize, hashToBytes(c, hash))
185+
p = appendBlock(p, blockSize, pub.q[1:1+len(pub.q)/2])
186+
p = appendBlock(p, blockSize, pub.q[1+len(pub.q)/2:])
156187
if kdsa(functionCode, &params) != 0 {
157188
return errors.New("invalid signature")
158189
}

0 commit comments

Comments
 (0)