github.com/defanghe/fabric@v2.1.1+incompatible/core/common/ccpackage/ccpackage.go (about) 1 /* 2 Copyright IBM Corp. 2016-2019 All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package ccpackage 8 9 import ( 10 "bytes" 11 "errors" 12 "fmt" 13 14 "github.com/golang/protobuf/proto" 15 "github.com/hyperledger/fabric-protos-go/common" 16 "github.com/hyperledger/fabric-protos-go/peer" 17 "github.com/hyperledger/fabric/internal/pkg/identity" 18 "github.com/hyperledger/fabric/protoutil" 19 ) 20 21 // ExtractSignedCCDepSpec extracts the messages from the envelope 22 func ExtractSignedCCDepSpec(env *common.Envelope) (*common.ChannelHeader, *peer.SignedChaincodeDeploymentSpec, error) { 23 p := &common.Payload{} 24 err := proto.Unmarshal(env.Payload, p) 25 if err != nil { 26 return nil, nil, err 27 } 28 if p.Header == nil { 29 return nil, nil, errors.New("channel header cannot be nil") 30 } 31 ch := &common.ChannelHeader{} 32 err = proto.Unmarshal(p.Header.ChannelHeader, ch) 33 if err != nil { 34 return nil, nil, err 35 } 36 37 sp := &peer.SignedChaincodeDeploymentSpec{} 38 err = proto.Unmarshal(p.Data, sp) 39 if err != nil { 40 return nil, nil, err 41 } 42 43 return ch, sp, nil 44 } 45 46 // This file provides functions for helping with the chaincode install 47 // package workflow. In particular 48 // OwnerCreateSignedCCDepSpec - each owner creates signs the package using the same deploy 49 // CreateSignedCCDepSpecForInstall - an admin or owner creates the package to be installed 50 // using the packages from OwnerCreateSignedCCDepSpec 51 52 // ValidateCip validate the endorsed package against the base package 53 func ValidateCip(baseCip, otherCip *peer.SignedChaincodeDeploymentSpec) error { 54 if baseCip == nil || otherCip == nil { 55 panic("do not call with nil parameters") 56 } 57 58 if (baseCip.OwnerEndorsements == nil && otherCip.OwnerEndorsements != nil) || (baseCip.OwnerEndorsements != nil && otherCip.OwnerEndorsements == nil) { 59 return fmt.Errorf("endorsements should either be both nil or not nil") 60 } 61 62 bN := len(baseCip.OwnerEndorsements) 63 oN := len(otherCip.OwnerEndorsements) 64 if bN > 1 || oN > 1 { 65 return fmt.Errorf("expect utmost 1 endorsement from a owner") 66 } 67 68 if bN != oN { 69 return fmt.Errorf("Rule-all packages should be endorsed or none should be endorsed failed for (%d, %d)", bN, oN) 70 } 71 72 if !bytes.Equal(baseCip.ChaincodeDeploymentSpec, otherCip.ChaincodeDeploymentSpec) { 73 return fmt.Errorf("Rule-all deployment specs should match(%d, %d)", len(baseCip.ChaincodeDeploymentSpec), len(otherCip.ChaincodeDeploymentSpec)) 74 } 75 76 if !bytes.Equal(baseCip.InstantiationPolicy, otherCip.InstantiationPolicy) { 77 return fmt.Errorf("Rule-all instantiation policies should match(%d, %d)", len(baseCip.InstantiationPolicy), len(otherCip.InstantiationPolicy)) 78 } 79 80 return nil 81 } 82 83 func createSignedCCDepSpec(cdsbytes []byte, instpolicybytes []byte, endorsements []*peer.Endorsement) (*common.Envelope, error) { 84 if cdsbytes == nil { 85 return nil, fmt.Errorf("nil chaincode deployment spec") 86 } 87 88 if instpolicybytes == nil { 89 return nil, fmt.Errorf("nil instantiation policy") 90 } 91 92 // create SignedChaincodeDeploymentSpec... 93 cip := &peer.SignedChaincodeDeploymentSpec{ChaincodeDeploymentSpec: cdsbytes, InstantiationPolicy: instpolicybytes, OwnerEndorsements: endorsements} 94 95 //...and marshal it 96 cipbytes := protoutil.MarshalOrPanic(cip) 97 98 //use defaults (this is definitely ok for install package) 99 msgVersion := int32(0) 100 epoch := uint64(0) 101 chdr := protoutil.MakeChannelHeader(common.HeaderType_CHAINCODE_PACKAGE, msgVersion, "", epoch) 102 103 // create the payload 104 payl := &common.Payload{Header: &common.Header{ChannelHeader: protoutil.MarshalOrPanic(chdr)}, Data: cipbytes} 105 paylBytes, err := protoutil.GetBytesPayload(payl) 106 if err != nil { 107 return nil, err 108 } 109 110 // here's the unsigned envelope. The install package is endorsed if signingEntity != nil 111 return &common.Envelope{Payload: paylBytes}, nil 112 } 113 114 // CreateSignedCCDepSpecForInstall creates the final package from a set of packages signed by 115 // owners. This is similar to how the SDK assembles a TX from various proposal 116 // responses from the signatures. 117 func CreateSignedCCDepSpecForInstall(pack []*common.Envelope) (*common.Envelope, error) { 118 if len(pack) == 0 { 119 return nil, errors.New("no packages provided to collate") 120 } 121 122 //rules... 123 // all packages must be endorsed or all packages should not be endorsed 124 // the chaincode deployment spec should be same 125 var baseCip *peer.SignedChaincodeDeploymentSpec 126 var err error 127 var endorsementExists bool 128 var endorsements []*peer.Endorsement 129 for n, r := range pack { 130 p := &common.Payload{} 131 if err = proto.Unmarshal(r.Payload, p); err != nil { 132 return nil, err 133 } 134 135 cip := &peer.SignedChaincodeDeploymentSpec{} 136 if err = proto.Unmarshal(p.Data, cip); err != nil { 137 return nil, err 138 } 139 140 //if its the first element, check if it has endorsement so we can 141 //enforce endorsement rules 142 if n == 0 { 143 baseCip = cip 144 //if it has endorsement, all other owners should have signed too 145 if len(cip.OwnerEndorsements) > 0 { 146 endorsementExists = true 147 endorsements = make([]*peer.Endorsement, len(pack)) 148 } 149 150 } else if err = ValidateCip(baseCip, cip); err != nil { 151 return nil, err 152 } 153 154 if endorsementExists { 155 endorsements[n] = cip.OwnerEndorsements[0] 156 } 157 } 158 159 return createSignedCCDepSpec(baseCip.ChaincodeDeploymentSpec, baseCip.InstantiationPolicy, endorsements) 160 } 161 162 // OwnerCreateSignedCCDepSpec creates a package from a ChaincodeDeploymentSpec and 163 // optionally endorses it 164 func OwnerCreateSignedCCDepSpec(cds *peer.ChaincodeDeploymentSpec, instPolicy *common.SignaturePolicyEnvelope, owner identity.SignerSerializer) (*common.Envelope, error) { 165 if cds == nil { 166 return nil, fmt.Errorf("invalid chaincode deployment spec") 167 } 168 169 if instPolicy == nil { 170 return nil, fmt.Errorf("must provide an instantiation policy") 171 } 172 173 cdsbytes := protoutil.MarshalOrPanic(cds) 174 175 instpolicybytes := protoutil.MarshalOrPanic(instPolicy) 176 177 var endorsements []*peer.Endorsement 178 //it is not mandatory (at this protoutil level) to have a signature 179 //this is especially convenient during dev/test 180 //it may be necessary to enforce it via a policy at a higher level 181 if owner != nil { 182 // serialize the signing identity 183 endorser, err := owner.Serialize() 184 if err != nil { 185 return nil, fmt.Errorf("Could not serialize the signing identity: %s", err) 186 } 187 188 // sign the concatenation of cds, instpolicy and the serialized endorser identity with this endorser's key 189 signature, err := owner.Sign(append(cdsbytes, append(instpolicybytes, endorser...)...)) 190 if err != nil { 191 return nil, fmt.Errorf("Could not sign the ccpackage, err %s", err) 192 } 193 194 // each owner starts off the endorsements with one element. All such endorsed 195 // packages will be collected in a final package by CreateSignedCCDepSpecForInstall 196 // when endorsements will have all the entries 197 endorsements = make([]*peer.Endorsement, 1) 198 199 endorsements[0] = &peer.Endorsement{Signature: signature, Endorser: endorser} 200 } 201 202 return createSignedCCDepSpec(cdsbytes, instpolicybytes, endorsements) 203 } 204 205 // SignExistingPackage adds a signature to a signed package. 206 func SignExistingPackage(env *common.Envelope, owner identity.SignerSerializer) (*common.Envelope, error) { 207 if owner == nil { 208 return nil, fmt.Errorf("owner not provided") 209 } 210 211 ch, sdepspec, err := ExtractSignedCCDepSpec(env) 212 if err != nil { 213 return nil, err 214 } 215 216 if ch == nil { 217 return nil, fmt.Errorf("channel header not found in the envelope") 218 } 219 220 if sdepspec == nil || sdepspec.ChaincodeDeploymentSpec == nil || sdepspec.InstantiationPolicy == nil || sdepspec.OwnerEndorsements == nil { 221 return nil, fmt.Errorf("invalid signed deployment spec") 222 } 223 224 // serialize the signing identity 225 endorser, err := owner.Serialize() 226 if err != nil { 227 return nil, fmt.Errorf("Could not serialize the signing identity: %s", err) 228 } 229 230 // sign the concatenation of cds, instpolicy and the serialized endorser identity with this endorser's key 231 signature, err := owner.Sign(append(sdepspec.ChaincodeDeploymentSpec, append(sdepspec.InstantiationPolicy, endorser...)...)) 232 if err != nil { 233 return nil, fmt.Errorf("Could not sign the ccpackage, err %s", err) 234 } 235 236 endorsements := append(sdepspec.OwnerEndorsements, &peer.Endorsement{Signature: signature, Endorser: endorser}) 237 238 return createSignedCCDepSpec(sdepspec.ChaincodeDeploymentSpec, sdepspec.InstantiationPolicy, endorsements) 239 }