github.com/defanghe/fabric@v2.1.1+incompatible/internal/cryptogen/csp/csp.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 package csp 7 8 import ( 9 "crypto" 10 "crypto/ecdsa" 11 "crypto/elliptic" 12 "crypto/rand" 13 "crypto/x509" 14 "encoding/asn1" 15 "encoding/pem" 16 "io" 17 "io/ioutil" 18 "math/big" 19 "os" 20 "path/filepath" 21 "strings" 22 23 "github.com/pkg/errors" 24 ) 25 26 // LoadPrivateKey loads a private key from a file in keystorePath. It looks 27 // for a file ending in "_sk" and expects a PEM-encoded PKCS8 EC private key. 28 func LoadPrivateKey(keystorePath string) (*ecdsa.PrivateKey, error) { 29 var priv *ecdsa.PrivateKey 30 31 walkFunc := func(path string, info os.FileInfo, pathErr error) error { 32 33 if !strings.HasSuffix(path, "_sk") { 34 return nil 35 } 36 37 rawKey, err := ioutil.ReadFile(path) 38 if err != nil { 39 return err 40 } 41 42 priv, err = parsePrivateKeyPEM(rawKey) 43 if err != nil { 44 return errors.WithMessage(err, path) 45 } 46 47 return nil 48 } 49 50 err := filepath.Walk(keystorePath, walkFunc) 51 if err != nil { 52 return nil, err 53 } 54 55 return priv, err 56 } 57 58 func parsePrivateKeyPEM(rawKey []byte) (*ecdsa.PrivateKey, error) { 59 block, _ := pem.Decode(rawKey) 60 if block == nil { 61 return nil, errors.New("bytes are not PEM encoded") 62 } 63 64 key, err := x509.ParsePKCS8PrivateKey(block.Bytes) 65 if err != nil { 66 return nil, errors.WithMessage(err, "pem bytes are not PKCS8 encoded ") 67 } 68 69 priv, ok := key.(*ecdsa.PrivateKey) 70 if !ok { 71 return nil, errors.New("pem bytes do not contain an EC private key") 72 } 73 return priv, nil 74 } 75 76 // GeneratePrivateKey creates an EC private key using a P-256 curve and stores 77 // it in keystorePath. 78 func GeneratePrivateKey(keystorePath string) (*ecdsa.PrivateKey, error) { 79 80 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 81 if err != nil { 82 return nil, errors.WithMessage(err, "failed to generate private key") 83 } 84 85 pkcs8Encoded, err := x509.MarshalPKCS8PrivateKey(priv) 86 if err != nil { 87 return nil, errors.WithMessage(err, "failed to marshal private key") 88 } 89 90 pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: pkcs8Encoded}) 91 92 keyFile := filepath.Join(keystorePath, "priv_sk") 93 err = ioutil.WriteFile(keyFile, pemEncoded, 0600) 94 if err != nil { 95 return nil, errors.WithMessagef(err, "failed to save private key to file %s", keyFile) 96 } 97 98 return priv, err 99 } 100 101 /** 102 ECDSA signer implements the crypto.Signer interface for ECDSA keys. The 103 Sign method ensures signatures are created with Low S values since Fabric 104 normalizes all signatures to Low S. 105 See https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#low_s 106 for more detail. 107 */ 108 type ECDSASigner struct { 109 PrivateKey *ecdsa.PrivateKey 110 } 111 112 // Public returns the ecdsa.PublicKey associated with PrivateKey. 113 func (e *ECDSASigner) Public() crypto.PublicKey { 114 return &e.PrivateKey.PublicKey 115 } 116 117 // Sign signs the digest and ensures that signatures use the Low S value. 118 func (e *ECDSASigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { 119 r, s, err := ecdsa.Sign(rand, e.PrivateKey, digest) 120 if err != nil { 121 return nil, err 122 } 123 124 // ensure Low S signatures 125 sig := toLowS( 126 e.PrivateKey.PublicKey, 127 ECDSASignature{ 128 R: r, 129 S: s, 130 }, 131 ) 132 133 // return marshaled aignature 134 return asn1.Marshal(sig) 135 } 136 137 /** 138 When using ECDSA, both (r,s) and (r, -s mod n) are valid signatures. In order 139 to protect against signature malleability attacks, Fabric normalizes all 140 signatures to a canonical form where s is at most half the order of the curve. 141 In order to make signatures compliant with what Fabric expects, toLowS creates 142 signatures in this canonical form. 143 */ 144 func toLowS(key ecdsa.PublicKey, sig ECDSASignature) ECDSASignature { 145 // calculate half order of the curve 146 halfOrder := new(big.Int).Div(key.Curve.Params().N, big.NewInt(2)) 147 // check if s is greater than half order of curve 148 if sig.S.Cmp(halfOrder) == 1 { 149 // Set s to N - s so that s will be less than or equal to half order 150 sig.S.Sub(key.Params().N, sig.S) 151 } 152 return sig 153 } 154 155 type ECDSASignature struct { 156 R, S *big.Int 157 }