github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/cmd/common/signer/signer.go (about) 1 /* 2 Copyright hechain. 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 "strings" 19 20 "github.com/hechain20/hechain/bccsp/utils" 21 "github.com/hechain20/hechain/common/util" 22 "github.com/hechain20/hechain/protoutil" 23 "github.com/hyperledger/fabric-protos-go/msp" 24 "github.com/pkg/errors" 25 ) 26 27 // Config holds the configuration for 28 // creation of a Signer 29 type Config struct { 30 MSPID string 31 IdentityPath string 32 KeyPath string 33 } 34 35 // Signer signs messages. 36 // TODO: Ideally we'd use an MSP to be agnostic, but since it's impossible to 37 // initialize an MSP without a CA cert that signs the signing identity, 38 // this will do for now. 39 type Signer struct { 40 key *ecdsa.PrivateKey 41 Creator []byte 42 } 43 44 func (si *Signer) Serialize() ([]byte, error) { 45 return si.Creator, nil 46 } 47 48 // NewSigner creates a new Signer out of the given configuration 49 func NewSigner(conf Config) (*Signer, error) { 50 sId, err := serializeIdentity(conf.IdentityPath, conf.MSPID) 51 if err != nil { 52 return nil, errors.WithStack(err) 53 } 54 key, err := loadPrivateKey(conf.KeyPath) 55 if err != nil { 56 return nil, errors.WithStack(err) 57 } 58 return &Signer{ 59 Creator: sId, 60 key: key, 61 }, nil 62 } 63 64 func serializeIdentity(clientCert string, mspID string) ([]byte, error) { 65 b, err := ioutil.ReadFile(clientCert) 66 if err != nil { 67 return nil, errors.WithStack(err) 68 } 69 if err := validateEnrollmentCertificate(b); err != nil { 70 return nil, err 71 } 72 sId := &msp.SerializedIdentity{ 73 Mspid: mspID, 74 IdBytes: b, 75 } 76 return protoutil.MarshalOrPanic(sId), nil 77 } 78 79 func validateEnrollmentCertificate(b []byte) error { 80 bl, _ := pem.Decode(b) 81 if bl == nil { 82 return errors.Errorf("enrollment certificate isn't a valid PEM block") 83 } 84 85 if bl.Type != "CERTIFICATE" { 86 return errors.Errorf("enrollment certificate should be a certificate, got a %s instead", strings.ToLower(bl.Type)) 87 } 88 89 if _, err := x509.ParseCertificate(bl.Bytes); err != nil { 90 return errors.Errorf("enrollment certificate is not a valid x509 certificate: %v", err) 91 } 92 return nil 93 } 94 95 func (si *Signer) Sign(msg []byte) ([]byte, error) { 96 digest := util.ComputeSHA256(msg) 97 return signECDSA(si.key, digest) 98 } 99 100 func loadPrivateKey(file string) (*ecdsa.PrivateKey, error) { 101 b, err := ioutil.ReadFile(file) 102 if err != nil { 103 return nil, errors.WithStack(err) 104 } 105 bl, _ := pem.Decode(b) 106 if bl == nil { 107 return nil, errors.Errorf("failed to decode PEM block from %s", file) 108 } 109 key, err := parsePrivateKey(bl.Bytes) 110 if err != nil { 111 return nil, err 112 } 113 return key.(*ecdsa.PrivateKey), nil 114 } 115 116 // Based on crypto/tls/tls.go but modified for Fabric: 117 func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { 118 // OpenSSL 1.0.0 generates PKCS#8 keys. 119 if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { 120 switch key := key.(type) { 121 // Fabric only supports ECDSA at the moment. 122 case *ecdsa.PrivateKey: 123 return key, nil 124 default: 125 return nil, errors.Errorf("found unknown private key type (%T) in PKCS#8 wrapping", key) 126 } 127 } 128 129 // OpenSSL ecparam generates SEC1 EC private keys for ECDSA. 130 key, err := x509.ParseECPrivateKey(der) 131 if err != nil { 132 return nil, errors.Errorf("failed to parse private key: %v", err) 133 } 134 135 return key, nil 136 } 137 138 func signECDSA(k *ecdsa.PrivateKey, digest []byte) (signature []byte, err error) { 139 r, s, err := ecdsa.Sign(rand.Reader, k, digest) 140 if err != nil { 141 return nil, err 142 } 143 144 s, err = utils.ToLowS(&k.PublicKey, s) 145 if err != nil { 146 return nil, err 147 } 148 149 return marshalECDSASignature(r, s) 150 } 151 152 func marshalECDSASignature(r, s *big.Int) ([]byte, error) { 153 return asn1.Marshal(ECDSASignature{r, s}) 154 } 155 156 type ECDSASignature struct { 157 R, S *big.Int 158 }