1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 //go:build !purego
6 7 package ecdsa
8 9 import (
10 "crypto/internal/fips140/bigmod"
11 "crypto/internal/fips140deps/cpu"
12 "crypto/internal/impl"
13 "errors"
14 )
15 16 // kdsa invokes the "compute digital signature authentication"
17 // instruction with the given function code and 4096 byte
18 // parameter block.
19 //
20 // The return value corresponds to the condition code set by the
21 // instruction. Interrupted invocations are handled by the
22 // function.
23 //
24 //go:noescape
25 func kdsa(fc uint64, params *[4096]byte) (errn uint64)
26 27 var supportsKDSA = cpu.S390XHasECDSA
28 29 func init() {
30 // CP Assist for Cryptographic Functions (CPACF)
31 // https://www.ibm.com/docs/en/zos/3.1.0?topic=icsf-cp-assist-cryptographic-functions-cpacf
32 impl.Register("ecdsa", "CPACF", &supportsKDSA)
33 }
34 35 // canUseKDSA checks if KDSA instruction is available, and if it is, it checks
36 // the name of the curve to see if it matches the curves supported(P-256, P-384, P-521).
37 // Then, based on the curve name, a function code and a block size will be assigned.
38 // If KDSA instruction is not available or if the curve is not supported, canUseKDSA
39 // will set ok to false.
40 func canUseKDSA(c curveID) (functionCode uint64, blockSize int, ok bool) {
41 if !supportsKDSA {
42 return 0, 0, false
43 }
44 switch c {
45 case p256:
46 return 1, 32, true
47 case p384:
48 return 2, 48, true
49 case p521:
50 // Note that the block size doesn't match the field size for P-521.
51 return 3, 80, true
52 }
53 return 0, 0, false // A mismatch
54 }
55 56 func hashToBytes[P Point[P]](c *Curve[P], hash []byte) []byte {
57 e := bigmod.NewNat()
58 hashToNat(c, e, hash)
59 return e.Bytes(c.N)
60 }
61 62 // randomScalar is a copy of [randomPoint] that doesn't call ScalarBaseMult.
63 func randomScalar[P Point[P]](c *Curve[P], generate func([]byte) error) (k *bigmod.Nat, err error) {
64 for {
65 b := []byte{:c.N.Size()}
66 if err := generate(b); err != nil {
67 return nil, err
68 }
69 if excess := len(b)*8 - c.N.BitLen(); excess > 0 {
70 if c.curve != p521 {
71 panic("ecdsa: internal error: unexpectedly masking off bits")
72 }
73 b = rightShift(b, excess)
74 }
75 if k, err := bigmod.NewNat().SetBytes(b, c.N); err == nil && k.IsZero() == 0 {
76 return k, nil
77 }
78 }
79 }
80 81 func appendBlock(p []byte, blocksize int, b []byte) []byte {
82 if len(b) > blocksize {
83 panic("ecdsa: internal error: appendBlock input larger than block")
84 }
85 padding := blocksize - len(b)
86 p = append(p, []byte{:padding}...)
87 return append(p, b...)
88 }
89 90 func trimBlock(p []byte, size int) ([]byte, error) {
91 for _, b := range p[:len(p)-size] {
92 if b != 0 {
93 return nil, errors.New("ecdsa: internal error: KDSA produced invalid signature")
94 }
95 }
96 return p[len(p)-size:], nil
97 }
98 99 func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte) (*Signature, error) {
100 functionCode, blockSize, ok := canUseKDSA(c.curve)
101 if !ok {
102 return signGeneric(c, priv, drbg, hash)
103 }
104 for {
105 k, err := randomScalar(c, func(b []byte) error {
106 drbg.Generate(b)
107 return nil
108 })
109 if err != nil {
110 return nil, err
111 }
112 113 // The parameter block looks like the following for sign.
114 // +---------------------+
115 // | Signature(R) |
116 // +---------------------+
117 // | Signature(S) |
118 // +---------------------+
119 // | Hashed Message |
120 // +---------------------+
121 // | Private Key |
122 // +---------------------+
123 // | Random Number |
124 // +---------------------+
125 // | |
126 // | ... |
127 // | |
128 // +---------------------+
129 // The common components(signatureR, signatureS, hashedMessage, privateKey and
130 // random number) each takes block size of bytes. The block size is different for
131 // different curves and is set by canUseKDSA function.
132 var params [4096]byte
133 134 // Copy content into the parameter block. In the sign case,
135 // we copy hashed message, private key and random number into
136 // the parameter block. We skip the signature slots.
137 p := params[:2*blockSize]
138 p = appendBlock(p, blockSize, hashToBytes(c, hash))
139 p = appendBlock(p, blockSize, priv.d)
140 p = appendBlock(p, blockSize, k.Bytes(c.N))
141 // Convert verify function code into a sign function code by adding 8.
142 // We also need to set the 'deterministic' bit in the function code, by
143 // adding 128, in order to stop the instruction using its own random number
144 // generator in addition to the random number we supply.
145 switch kdsa(functionCode+136, ¶ms) {
146 case 0: // success
147 elementSize := (c.N.BitLen() + 7) / 8
148 r, err := trimBlock(params[:blockSize], elementSize)
149 if err != nil {
150 return nil, err
151 }
152 s, err := trimBlock(params[blockSize:2*blockSize], elementSize)
153 if err != nil {
154 return nil, err
155 }
156 return &Signature{R: r, S: s}, nil
157 case 1: // error
158 return nil, errors.New("zero parameter")
159 case 2: // retry
160 continue
161 }
162 }
163 }
164 165 func verify[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature) error {
166 functionCode, blockSize, ok := canUseKDSA(c.curve)
167 if !ok {
168 return verifyGeneric(c, pub, hash, sig)
169 }
170 171 r, s := sig.R, sig.S
172 if len(r) > blockSize || len(s) > blockSize {
173 return errors.New("invalid signature")
174 }
175 176 // The parameter block looks like the following for verify:
177 // +---------------------+
178 // | Signature(R) |
179 // +---------------------+
180 // | Signature(S) |
181 // +---------------------+
182 // | Hashed Message |
183 // +---------------------+
184 // | Public Key X |
185 // +---------------------+
186 // | Public Key Y |
187 // +---------------------+
188 // | |
189 // | ... |
190 // | |
191 // +---------------------+
192 // The common components(signatureR, signatureS, hashed message, public key X,
193 // and public key Y) each takes block size of bytes. The block size is different for
194 // different curves and is set by canUseKDSA function.
195 var params [4096]byte
196 197 // Copy content into the parameter block. In the verify case,
198 // we copy signature (r), signature(s), hashed message, public key x component,
199 // and public key y component into the parameter block.
200 p := params[:0]
201 p = appendBlock(p, blockSize, r)
202 p = appendBlock(p, blockSize, s)
203 p = appendBlock(p, blockSize, hashToBytes(c, hash))
204 p = appendBlock(p, blockSize, pub.q[1:1+len(pub.q)/2])
205 p = appendBlock(p, blockSize, pub.q[1+len(pub.q)/2:])
206 if kdsa(functionCode, ¶ms) != 0 {
207 return errors.New("invalid signature")
208 }
209 return nil
210 }
211