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 package ecdsa 6 7 import ( 8 "crypto/elliptic" 9 "errors" 10 "internal/cpu" 11 "io" 12 "math/big" 13 ) 14 15 // kdsa invokes the "compute digital signature authentication" 16 // instruction with the given function code and 4096 byte 17 // parameter block. 18 // 19 // The return value corresponds to the condition code set by the 20 // instruction. Interrupted invocations are handled by the 21 // function. 22 // 23 //go:noescape 24 func kdsa(fc uint64, params *[4096]byte) (errn uint64) 25 26 // testingDisableKDSA forces the generic fallback path. It must only be set in tests. 27 var testingDisableKDSA bool 28 29 // canUseKDSA checks if KDSA instruction is available, and if it is, it checks 30 // the name of the curve to see if it matches the curves supported(P-256, P-384, P-521). 31 // Then, based on the curve name, a function code and a block size will be assigned. 32 // If KDSA instruction is not available or if the curve is not supported, canUseKDSA 33 // will set ok to false. 34 func canUseKDSA(c elliptic.Curve) (functionCode uint64, blockSize int, ok bool) { 35 if testingDisableKDSA { 36 return 0, 0, false 37 } 38 if !cpu.S390X.HasECDSA { 39 return 0, 0, false 40 } 41 switch c.Params().Name { 42 case "P-256": 43 return 1, 32, true 44 case "P-384": 45 return 2, 48, true 46 case "P-521": 47 return 3, 80, true 48 } 49 return 0, 0, false // A mismatch 50 } 51 52 func hashToBytes(dst, hash []byte, c elliptic.Curve) { 53 l := len(dst) 54 if n := c.Params().N.BitLen(); n == l*8 { 55 // allocation free path for curves with a length that is a whole number of bytes 56 if len(hash) >= l { 57 // truncate hash 58 copy(dst, hash[:l]) 59 return 60 } 61 // pad hash with leading zeros 62 p := l - len(hash) 63 for i := 0; i < p; i++ { 64 dst[i] = 0 65 } 66 copy(dst[p:], hash) 67 return 68 } 69 // TODO(mundaym): avoid hashToInt call here 70 hashToInt(hash, c).FillBytes(dst) 71 } 72 73 func signAsm(priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, err error) { 74 c := priv.Curve 75 functionCode, blockSize, ok := canUseKDSA(c) 76 if !ok { 77 return nil, errNoAsm 78 } 79 for { 80 var k *big.Int 81 k, err = randFieldElement(c, csprng) 82 if err != nil { 83 return nil, err 84 } 85 86 // The parameter block looks like the following for sign. 87 // +---------------------+ 88 // | Signature(R) | 89 // +---------------------+ 90 // | Signature(S) | 91 // +---------------------+ 92 // | Hashed Message | 93 // +---------------------+ 94 // | Private Key | 95 // +---------------------+ 96 // | Random Number | 97 // +---------------------+ 98 // | | 99 // | ... | 100 // | | 101 // +---------------------+ 102 // The common components(signatureR, signatureS, hashedMessage, privateKey and 103 // random number) each takes block size of bytes. The block size is different for 104 // different curves and is set by canUseKDSA function. 105 var params [4096]byte 106 107 // Copy content into the parameter block. In the sign case, 108 // we copy hashed message, private key and random number into 109 // the parameter block. 110 hashToBytes(params[2*blockSize:3*blockSize], hash, c) 111 priv.D.FillBytes(params[3*blockSize : 4*blockSize]) 112 k.FillBytes(params[4*blockSize : 5*blockSize]) 113 // Convert verify function code into a sign function code by adding 8. 114 // We also need to set the 'deterministic' bit in the function code, by 115 // adding 128, in order to stop the instruction using its own random number 116 // generator in addition to the random number we supply. 117 switch kdsa(functionCode+136, ¶ms) { 118 case 0: // success 119 return encodeSignature(params[:blockSize], params[blockSize:2*blockSize]) 120 case 1: // error 121 return nil, errZeroParam 122 case 2: // retry 123 continue 124 } 125 panic("unreachable") 126 } 127 } 128 129 func verifyAsm(pub *PublicKey, hash []byte, sig []byte) error { 130 c := pub.Curve 131 functionCode, blockSize, ok := canUseKDSA(c) 132 if !ok { 133 return errNoAsm 134 } 135 136 r, s, err := parseSignature(sig) 137 if err != nil { 138 return err 139 } 140 if len(r) > blockSize || len(s) > blockSize { 141 return errors.New("invalid signature") 142 } 143 144 // The parameter block looks like the following for verify: 145 // +---------------------+ 146 // | Signature(R) | 147 // +---------------------+ 148 // | Signature(S) | 149 // +---------------------+ 150 // | Hashed Message | 151 // +---------------------+ 152 // | Public Key X | 153 // +---------------------+ 154 // | Public Key Y | 155 // +---------------------+ 156 // | | 157 // | ... | 158 // | | 159 // +---------------------+ 160 // The common components(signatureR, signatureS, hashed message, public key X, 161 // and public key Y) each takes block size of bytes. The block size is different for 162 // different curves and is set by canUseKDSA function. 163 var params [4096]byte 164 165 // Copy content into the parameter block. In the verify case, 166 // we copy signature (r), signature(s), hashed message, public key x component, 167 // and public key y component into the parameter block. 168 copy(params[0*blockSize+blockSize-len(r):], r) 169 copy(params[1*blockSize+blockSize-len(s):], s) 170 hashToBytes(params[2*blockSize:3*blockSize], hash, c) 171 pub.X.FillBytes(params[3*blockSize : 4*blockSize]) 172 pub.Y.FillBytes(params[4*blockSize : 5*blockSize]) 173 if kdsa(functionCode, ¶ms) != 0 { 174 return errors.New("invalid signature") 175 } 176 return nil 177 } 178