github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/hyperledger/fabric-config/configtx/signer.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package configtx 8 9 import ( 10 "crypto" 11 "crypto/rand" 12 "encoding/asn1" 13 "encoding/pem" 14 "fmt" 15 "github.com/hellobchain/newcryptosm" 16 "github.com/hellobchain/newcryptosm/ecdsa" 17 "github.com/hellobchain/newcryptosm/x509" 18 "io" 19 "math/big" 20 21 "github.com/golang/protobuf/proto" 22 cb "github.com/hyperledger/fabric-protos-go/common" 23 mb "github.com/hyperledger/fabric-protos-go/msp" 24 ) 25 26 // SigningIdentity is an MSP Identity that can be used to sign configuration 27 // updates. 28 type SigningIdentity struct { 29 Certificate *x509.Certificate 30 PrivateKey crypto.PrivateKey 31 MSPID string 32 } 33 34 type ecdsaSignature struct { 35 R, S *big.Int 36 } 37 38 // Public returns the public key associated with this signing 39 // identity's certificate. 40 func (s *SigningIdentity) Public() crypto.PublicKey { 41 return s.Certificate.PublicKey 42 } 43 44 // Sign performs ECDSA sign with this signing identity's private key on the 45 // given message hashed using SHA-256. It ensures signatures are created with 46 // Low S values since Fabric normalizes all signatures to Low S. 47 // See https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#low_s 48 // for more detail. 49 func (s *SigningIdentity) Sign(reader io.Reader, msg []byte, opts crypto.SignerOpts) (signature []byte, err error) { 50 switch pk := s.PrivateKey.(type) { 51 case *ecdsa.PrivateKey: 52 hasher := newcryptosm.SHA256.New() 53 if ecdsa.IsSM2(pk.Params()) { 54 hasher = newcryptosm.SM3.New() 55 } 56 hasher.Write(msg) 57 digest := hasher.Sum(nil) 58 59 rr, ss, err := ecdsa.Sign(reader, pk, digest) 60 if err != nil { 61 return nil, err 62 } 63 64 // ensure Low S signatures 65 sig := toLowS( 66 pk.PublicKey, 67 ecdsaSignature{ 68 R: rr, 69 S: ss, 70 }, 71 ) 72 73 return asn1.Marshal(sig) 74 default: 75 return nil, fmt.Errorf("signing with private key of type %T not supported", pk) 76 } 77 } 78 79 // toLows normalizes all signatures to a canonical form where s is at most 80 // half the order of the curve. By doing so, it compliant with what Fabric 81 // expected as well as protect against signature malleability attacks. 82 func toLowS(key ecdsa.PublicKey, sig ecdsaSignature) ecdsaSignature { 83 if ecdsa.IsSM2(key.Params()) { 84 return sig 85 } 86 87 // calculate half order of the curve 88 halfOrder := new(big.Int).Div(key.Curve.Params().N, big.NewInt(2)) 89 // check if s is greater than half order of curve 90 if sig.S.Cmp(halfOrder) == 1 { 91 // Set s to N - s so that s will be less than or equal to half order 92 sig.S.Sub(key.Params().N, sig.S) 93 } 94 95 return sig 96 } 97 98 // CreateConfigSignature creates a config signature for the the given configuration 99 // update using the specified signing identity. 100 func (s *SigningIdentity) CreateConfigSignature(marshaledUpdate []byte) (*cb.ConfigSignature, error) { 101 signatureHeader, err := s.signatureHeader() 102 if err != nil { 103 return nil, fmt.Errorf("creating signature header: %v", err) 104 } 105 106 header, err := proto.Marshal(signatureHeader) 107 if err != nil { 108 return nil, fmt.Errorf("marshaling signature header: %v", err) 109 } 110 111 configSignature := &cb.ConfigSignature{ 112 SignatureHeader: header, 113 } 114 115 configSignature.Signature, err = s.Sign( 116 rand.Reader, 117 concatenateBytes(configSignature.SignatureHeader, marshaledUpdate), 118 nil, 119 ) 120 if err != nil { 121 return nil, fmt.Errorf("signing config update: %v", err) 122 } 123 124 return configSignature, nil 125 } 126 127 // SignEnvelope signs an envelope using the SigningIdentity. 128 func (s *SigningIdentity) SignEnvelope(e *cb.Envelope) error { 129 signatureHeader, err := s.signatureHeader() 130 if err != nil { 131 return fmt.Errorf("creating signature header: %v", err) 132 } 133 134 sHeader, err := proto.Marshal(signatureHeader) 135 if err != nil { 136 return fmt.Errorf("marshaling signature header: %v", err) 137 } 138 139 payload := &cb.Payload{} 140 err = proto.Unmarshal(e.Payload, payload) 141 if err != nil { 142 return fmt.Errorf("unmarshaling envelope payload: %v", err) 143 } 144 payload.Header.SignatureHeader = sHeader 145 146 payloadBytes, err := proto.Marshal(payload) 147 if err != nil { 148 return fmt.Errorf("marshaling payload: %v", err) 149 } 150 151 sig, err := s.Sign(rand.Reader, payloadBytes, nil) 152 if err != nil { 153 return fmt.Errorf("signing envelope payload: %v", err) 154 } 155 156 e.Payload = payloadBytes 157 e.Signature = sig 158 159 return nil 160 } 161 162 func (s *SigningIdentity) signatureHeader() (*cb.SignatureHeader, error) { 163 pemBytes := pem.EncodeToMemory(&pem.Block{ 164 Type: "CERTIFICATE", 165 Bytes: s.Certificate.Raw, 166 }) 167 168 idBytes, err := proto.Marshal(&mb.SerializedIdentity{ 169 Mspid: s.MSPID, 170 IdBytes: pemBytes, 171 }) 172 if err != nil { 173 return nil, fmt.Errorf("marshaling serialized identity: %v", err) 174 } 175 176 nonce, err := newNonce() 177 if err != nil { 178 return nil, err 179 } 180 181 return &cb.SignatureHeader{ 182 Creator: idBytes, 183 Nonce: nonce, 184 }, nil 185 } 186 187 // newNonce generates a 24-byte nonce using the crypto/rand package. 188 func newNonce() ([]byte, error) { 189 nonce := make([]byte, 24) 190 191 _, err := rand.Read(nonce) 192 if err != nil { 193 return nil, fmt.Errorf("failed to get random bytes: %v", err) 194 } 195 196 return nonce, nil 197 }