github.com/renegr87/renegr87@v2.1.1+incompatible/core/common/ccprovider/sigcdspackage.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package ccprovider 18 19 import ( 20 "bytes" 21 "fmt" 22 "io/ioutil" 23 "os" 24 25 "github.com/golang/protobuf/proto" 26 "github.com/hyperledger/fabric-protos-go/common" 27 pb "github.com/hyperledger/fabric-protos-go/peer" 28 "github.com/hyperledger/fabric/bccsp" 29 "github.com/hyperledger/fabric/bccsp/factory" 30 "github.com/hyperledger/fabric/core/common/ccpackage" 31 ) 32 33 //----- SignedCDSData ------ 34 35 //SignedCDSData is data stored in the LSCC on instantiation of a CC 36 //for SignedCDSPackage. This needs to be serialized for ChaincodeData 37 //hence the protobuf format 38 type SignedCDSData struct { 39 CodeHash []byte `protobuf:"bytes,1,opt,name=hash"` 40 MetaDataHash []byte `protobuf:"bytes,2,opt,name=metadatahash"` 41 SignatureHash []byte `protobuf:"bytes,3,opt,name=signaturehash"` 42 } 43 44 //----implement functions needed from proto.Message for proto's mar/unmarshal functions 45 46 //Reset resets 47 func (data *SignedCDSData) Reset() { *data = SignedCDSData{} } 48 49 //String converts to string 50 func (data *SignedCDSData) String() string { return proto.CompactTextString(data) } 51 52 //ProtoMessage just exists to make proto happy 53 func (*SignedCDSData) ProtoMessage() {} 54 55 //Equals data equals other 56 func (data *SignedCDSData) Equals(other *SignedCDSData) bool { 57 return other != nil && 58 bytes.Equal(data.CodeHash, other.CodeHash) && 59 bytes.Equal(data.MetaDataHash, other.MetaDataHash) && 60 bytes.Equal(data.SignatureHash, other.SignatureHash) 61 } 62 63 //-------- SignedCDSPackage --------- 64 65 //SignedCDSPackage encapsulates SignedChaincodeDeploymentSpec. 66 type SignedCDSPackage struct { 67 buf []byte 68 depSpec *pb.ChaincodeDeploymentSpec 69 sDepSpec *pb.SignedChaincodeDeploymentSpec 70 env *common.Envelope 71 data *SignedCDSData 72 datab []byte 73 id []byte 74 GetHasher GetHasher 75 } 76 77 // GetId gets the fingerprint of the chaincode based on package computation 78 func (ccpack *SignedCDSPackage) GetId() []byte { 79 //this has to be after creating a package and initializing it 80 //If those steps fail, GetId() should never be called 81 if ccpack.id == nil { 82 panic("GetId called on uninitialized package") 83 } 84 return ccpack.id 85 } 86 87 // GetDepSpec gets the ChaincodeDeploymentSpec from the package 88 func (ccpack *SignedCDSPackage) GetDepSpec() *pb.ChaincodeDeploymentSpec { 89 //this has to be after creating a package and initializing it 90 //If those steps fail, GetDepSpec() should never be called 91 if ccpack.depSpec == nil { 92 panic("GetDepSpec called on uninitialized package") 93 } 94 return ccpack.depSpec 95 } 96 97 // GetInstantiationPolicy gets the instantiation policy from the package 98 func (ccpack *SignedCDSPackage) GetInstantiationPolicy() []byte { 99 if ccpack.sDepSpec == nil { 100 panic("GetInstantiationPolicy called on uninitialized package") 101 } 102 return ccpack.sDepSpec.InstantiationPolicy 103 } 104 105 // GetDepSpecBytes gets the serialized ChaincodeDeploymentSpec from the package 106 func (ccpack *SignedCDSPackage) GetDepSpecBytes() []byte { 107 //this has to be after creating a package and initializing it 108 //If those steps fail, GetDepSpecBytes() should never be called 109 if ccpack.sDepSpec == nil || ccpack.sDepSpec.ChaincodeDeploymentSpec == nil { 110 panic("GetDepSpecBytes called on uninitialized package") 111 } 112 return ccpack.sDepSpec.ChaincodeDeploymentSpec 113 } 114 115 // GetPackageObject gets the ChaincodeDeploymentSpec as proto.Message 116 func (ccpack *SignedCDSPackage) GetPackageObject() proto.Message { 117 return ccpack.env 118 } 119 120 // GetChaincodeData gets the ChaincodeData 121 func (ccpack *SignedCDSPackage) GetChaincodeData() *ChaincodeData { 122 //this has to be after creating a package and initializing it 123 //If those steps fail, GetChaincodeData() should never be called 124 if ccpack.depSpec == nil || ccpack.datab == nil || ccpack.id == nil { 125 panic("GetChaincodeData called on uninitialized package") 126 } 127 128 var instPolicy []byte 129 if ccpack.sDepSpec != nil { 130 instPolicy = ccpack.sDepSpec.InstantiationPolicy 131 } 132 133 return &ChaincodeData{ 134 Name: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name, 135 Version: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version, 136 Data: ccpack.datab, 137 Id: ccpack.id, 138 InstantiationPolicy: instPolicy, 139 } 140 } 141 142 func (ccpack *SignedCDSPackage) getCDSData(scds *pb.SignedChaincodeDeploymentSpec) ([]byte, []byte, *SignedCDSData, error) { 143 // check for nil argument. It is an assertion that getCDSData 144 // is never called on a package that did not go through/succeed 145 // package initialization. 146 if scds == nil { 147 panic("nil cds") 148 } 149 150 cds := &pb.ChaincodeDeploymentSpec{} 151 err := proto.Unmarshal(scds.ChaincodeDeploymentSpec, cds) 152 if err != nil { 153 return nil, nil, nil, err 154 } 155 156 if err = factory.InitFactories(nil); err != nil { 157 return nil, nil, nil, fmt.Errorf("Internal error, BCCSP could not be initialized : %s", err) 158 } 159 160 //get the hash object 161 hash, err := ccpack.GetHasher.GetHash(&bccsp.SHAOpts{}) 162 if err != nil { 163 return nil, nil, nil, err 164 } 165 166 scdsdata := &SignedCDSData{} 167 168 //get the code hash 169 hash.Write(cds.CodePackage) 170 scdsdata.CodeHash = hash.Sum(nil) 171 172 hash.Reset() 173 174 //get the metadata hash 175 hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Name)) 176 hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Version)) 177 178 scdsdata.MetaDataHash = hash.Sum(nil) 179 180 hash.Reset() 181 182 //get the signature hashes 183 if scds.InstantiationPolicy == nil { 184 return nil, nil, nil, fmt.Errorf("instantiation policy cannot be nil for chaincode (%s:%s)", cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version) 185 } 186 187 hash.Write(scds.InstantiationPolicy) 188 for _, o := range scds.OwnerEndorsements { 189 hash.Write(o.Endorser) 190 } 191 scdsdata.SignatureHash = hash.Sum(nil) 192 193 //marshall data 194 b, err := proto.Marshal(scdsdata) 195 if err != nil { 196 return nil, nil, nil, err 197 } 198 199 hash.Reset() 200 201 //compute the id 202 hash.Write(scdsdata.CodeHash) 203 hash.Write(scdsdata.MetaDataHash) 204 hash.Write(scdsdata.SignatureHash) 205 206 id := hash.Sum(nil) 207 208 return b, id, scdsdata, nil 209 } 210 211 // ValidateCC returns error if the chaincode is not found or if its not a 212 // ChaincodeDeploymentSpec 213 func (ccpack *SignedCDSPackage) ValidateCC(ccdata *ChaincodeData) error { 214 if ccpack.sDepSpec == nil { 215 return fmt.Errorf("uninitialized package") 216 } 217 218 if ccpack.sDepSpec.ChaincodeDeploymentSpec == nil { 219 return fmt.Errorf("signed chaincode deployment spec cannot be nil in a package") 220 } 221 222 if ccpack.depSpec == nil { 223 return fmt.Errorf("chaincode deployment spec cannot be nil in a package") 224 } 225 226 // This is a hack. LSCC expects a specific LSCC error when names are invalid so it 227 // has its own validation code. We can't use that error because of import cycles. 228 // Unfortunately, we also need to check if what have makes some sort of sense as 229 // protobuf will gladly deserialize garbage and there are paths where we assume that 230 // a successful unmarshal means everything works but, if it fails, we try to unmarshal 231 // into something different. 232 if !isPrintable(ccdata.Name) { 233 return fmt.Errorf("invalid chaincode name: %q", ccdata.Name) 234 } 235 236 if ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version { 237 return fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId) 238 } 239 240 otherdata := &SignedCDSData{} 241 err := proto.Unmarshal(ccdata.Data, otherdata) 242 if err != nil { 243 return err 244 } 245 246 if !ccpack.data.Equals(otherdata) { 247 return fmt.Errorf("data mismatch") 248 } 249 250 return nil 251 } 252 253 //InitFromBuffer sets the buffer if valid and returns ChaincodeData 254 func (ccpack *SignedCDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) { 255 256 env := &common.Envelope{} 257 err := proto.Unmarshal(buf, env) 258 if err != nil { 259 return nil, fmt.Errorf("failed to unmarshal envelope from bytes") 260 } 261 cHdr, sDepSpec, err := ccpackage.ExtractSignedCCDepSpec(env) 262 if err != nil { 263 return nil, err 264 } 265 266 if cHdr.Type != int32(common.HeaderType_CHAINCODE_PACKAGE) { 267 return nil, fmt.Errorf("invalid type of envelope for chaincode package") 268 } 269 270 depSpec := &pb.ChaincodeDeploymentSpec{} 271 err = proto.Unmarshal(sDepSpec.ChaincodeDeploymentSpec, depSpec) 272 if err != nil { 273 return nil, fmt.Errorf("error getting deployment spec") 274 } 275 276 databytes, id, data, err := ccpack.getCDSData(sDepSpec) 277 if err != nil { 278 return nil, err 279 } 280 281 ccpack.buf = buf 282 ccpack.sDepSpec = sDepSpec 283 ccpack.depSpec = depSpec 284 ccpack.env = env 285 ccpack.data = data 286 ccpack.datab = databytes 287 ccpack.id = id 288 289 return ccpack.GetChaincodeData(), nil 290 } 291 292 //InitFromFS returns the chaincode and its package from the file system 293 func (ccpack *SignedCDSPackage) InitFromFS(ccNameVersion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) { 294 return ccpack.InitFromPath(ccNameVersion, chaincodeInstallPath) 295 } 296 297 //InitFromPath returns the chaincode and its package from the file system 298 func (ccpack *SignedCDSPackage) InitFromPath(ccNameVersion string, path string) ([]byte, *pb.ChaincodeDeploymentSpec, error) { 299 300 buf, err := GetChaincodePackageFromPath(ccNameVersion, path) 301 if err != nil { 302 return nil, nil, err 303 } 304 305 if _, err = ccpack.InitFromBuffer(buf); err != nil { 306 return nil, nil, err 307 } 308 309 return ccpack.buf, ccpack.depSpec, nil 310 } 311 312 //PutChaincodeToFS - serializes chaincode to a package on the file system 313 func (ccpack *SignedCDSPackage) PutChaincodeToFS() error { 314 if ccpack.buf == nil { 315 return fmt.Errorf("uninitialized package") 316 } 317 318 if ccpack.id == nil { 319 return fmt.Errorf("id cannot be nil if buf is not nil") 320 } 321 322 if ccpack.sDepSpec == nil || ccpack.depSpec == nil { 323 return fmt.Errorf("depspec cannot be nil if buf is not nil") 324 } 325 326 if ccpack.env == nil { 327 return fmt.Errorf("env cannot be nil if buf and depspec are not nil") 328 } 329 330 if ccpack.data == nil { 331 return fmt.Errorf("nil data") 332 } 333 334 if ccpack.datab == nil { 335 return fmt.Errorf("nil data bytes") 336 } 337 338 ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name 339 ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version 340 341 //return error if chaincode exists 342 path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion) 343 if _, err := os.Stat(path); err == nil { 344 return fmt.Errorf("chaincode %s exists", path) 345 } 346 347 if err := ioutil.WriteFile(path, ccpack.buf, 0644); err != nil { 348 return err 349 } 350 351 return nil 352 }