github.com/ewagmig/fabric@v2.1.1+incompatible/cmd/common/signer/signer.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package signer 8 9 import ( 10 "crypto" 11 "crypto/ecdsa" 12 "crypto/rand" 13 "crypto/x509" 14 "encoding/asn1" 15 "encoding/pem" 16 "io/ioutil" 17 "math/big" 18 19 "github.com/hyperledger/fabric-protos-go/msp" 20 "github.com/hyperledger/fabric/bccsp/utils" 21 "github.com/hyperledger/fabric/common/util" 22 "github.com/hyperledger/fabric/protoutil" 23 "github.com/pkg/errors" 24 ) 25 26 // Config holds the configuration for 27 // creation of a Signer 28 type Config struct { 29 MSPID string 30 IdentityPath string 31 KeyPath string 32 } 33 34 // Signer signs messages. 35 // TODO: Ideally we'd use an MSP to be agnostic, but since it's impossible to 36 // initialize an MSP without a CA cert that signs the signing identity, 37 // this will do for now. 38 type Signer struct { 39 key *ecdsa.PrivateKey 40 Creator []byte 41 } 42 43 func (si *Signer) Serialize() ([]byte, error) { 44 return si.Creator, nil 45 } 46 47 // NewSigner creates a new Signer out of the given configuration 48 func NewSigner(conf Config) (*Signer, error) { 49 sId, err := serializeIdentity(conf.IdentityPath, conf.MSPID) 50 if err != nil { 51 return nil, errors.WithStack(err) 52 } 53 key, err := loadPrivateKey(conf.KeyPath) 54 if err != nil { 55 return nil, errors.WithStack(err) 56 } 57 return &Signer{ 58 Creator: sId, 59 key: key, 60 }, nil 61 } 62 63 func serializeIdentity(clientCert string, mspID string) ([]byte, error) { 64 b, err := ioutil.ReadFile(clientCert) 65 if err != nil { 66 return nil, errors.WithStack(err) 67 } 68 sId := &msp.SerializedIdentity{ 69 Mspid: mspID, 70 IdBytes: b, 71 } 72 return protoutil.MarshalOrPanic(sId), nil 73 } 74 75 func (si *Signer) Sign(msg []byte) ([]byte, error) { 76 digest := util.ComputeSHA256(msg) 77 return signECDSA(si.key, digest) 78 } 79 80 func loadPrivateKey(file string) (*ecdsa.PrivateKey, error) { 81 b, err := ioutil.ReadFile(file) 82 if err != nil { 83 return nil, errors.WithStack(err) 84 } 85 bl, _ := pem.Decode(b) 86 if bl == nil { 87 return nil, errors.Errorf("failed to decode PEM block from %s", file) 88 } 89 key, err := parsePrivateKey(bl.Bytes) 90 if err != nil { 91 return nil, err 92 } 93 return key.(*ecdsa.PrivateKey), nil 94 } 95 96 // Based on crypto/tls/tls.go but modified for Fabric: 97 func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { 98 // OpenSSL 1.0.0 generates PKCS#8 keys. 99 if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { 100 switch key := key.(type) { 101 // Fabric only supports ECDSA at the moment. 102 case *ecdsa.PrivateKey: 103 return key, nil 104 default: 105 return nil, errors.Errorf("found unknown private key type (%T) in PKCS#8 wrapping", key) 106 } 107 } 108 109 // OpenSSL ecparam generates SEC1 EC private keys for ECDSA. 110 key, err := x509.ParseECPrivateKey(der) 111 if err != nil { 112 return nil, errors.Errorf("failed to parse private key: %v", err) 113 } 114 115 return key, nil 116 } 117 118 func signECDSA(k *ecdsa.PrivateKey, digest []byte) (signature []byte, err error) { 119 r, s, err := ecdsa.Sign(rand.Reader, k, digest) 120 if err != nil { 121 return nil, err 122 } 123 124 s, err = utils.ToLowS(&k.PublicKey, s) 125 if err != nil { 126 return nil, err 127 } 128 129 return marshalECDSASignature(r, s) 130 } 131 132 func marshalECDSASignature(r, s *big.Int) ([]byte, error) { 133 return asn1.Marshal(ECDSASignature{r, s}) 134 } 135 136 type ECDSASignature struct { 137 R, S *big.Int 138 }