github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/swarm/storage/mru/signedupdate.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package mru 18 19 import ( 20 "bytes" 21 "hash" 22 23 "github.com/FusionFoundation/efsn/common" 24 "github.com/FusionFoundation/efsn/crypto" 25 "github.com/FusionFoundation/efsn/swarm/storage" 26 ) 27 28 // SignedResourceUpdate represents a resource update with all the necessary information to prove ownership of the resource 29 type SignedResourceUpdate struct { 30 resourceUpdate // actual content that will be put on the chunk, less signature 31 signature *Signature 32 updateAddr storage.Address // resulting chunk address for the update (not serialized, for internal use) 33 binaryData []byte // resulting serialized data (not serialized, for efficiency/internal use) 34 } 35 36 // Verify checks that signatures are valid and that the signer owns the resource to be updated 37 func (r *SignedResourceUpdate) Verify() (err error) { 38 if len(r.data) == 0 { 39 return NewError(ErrInvalidValue, "Update does not contain data") 40 } 41 if r.signature == nil { 42 return NewError(ErrInvalidSignature, "Missing signature field") 43 } 44 45 digest, err := r.GetDigest() 46 if err != nil { 47 return err 48 } 49 50 // get the address of the signer (which also checks that it's a valid signature) 51 ownerAddr, err := getOwner(digest, *r.signature) 52 if err != nil { 53 return err 54 } 55 56 if !bytes.Equal(r.updateAddr, r.UpdateAddr()) { 57 return NewError(ErrInvalidSignature, "Signature address does not match with ownerAddr") 58 } 59 60 // Check if who signed the resource update really owns the resource 61 if !verifyOwner(ownerAddr, r.metaHash, r.rootAddr) { 62 return NewErrorf(ErrUnauthorized, "signature is valid but signer does not own the resource: %v", err) 63 } 64 65 return nil 66 } 67 68 // Sign executes the signature to validate the resource 69 func (r *SignedResourceUpdate) Sign(signer Signer) error { 70 71 r.binaryData = nil //invalidate serialized data 72 digest, err := r.GetDigest() // computes digest and serializes into .binaryData 73 if err != nil { 74 return err 75 } 76 77 signature, err := signer.Sign(digest) 78 if err != nil { 79 return err 80 } 81 82 // Although the Signer interface returns the public address of the signer, 83 // recover it from the signature to see if they match 84 ownerAddress, err := getOwner(digest, signature) 85 if err != nil { 86 return NewError(ErrInvalidSignature, "Error verifying signature") 87 } 88 89 if ownerAddress != signer.Address() { // sanity check to make sure the Signer is declaring the same address used to sign! 90 return NewError(ErrInvalidSignature, "Signer address does not match ownerAddr") 91 } 92 93 r.signature = &signature 94 r.updateAddr = r.UpdateAddr() 95 return nil 96 } 97 98 // create an update chunk. 99 func (r *SignedResourceUpdate) toChunk() (storage.Chunk, error) { 100 101 // Check that the update is signed and serialized 102 // For efficiency, data is serialized during signature and cached in 103 // the binaryData field when computing the signature digest in .getDigest() 104 if r.signature == nil || r.binaryData == nil { 105 return nil, NewError(ErrInvalidSignature, "newUpdateChunk called without a valid signature or payload data. Call .Sign() first.") 106 } 107 108 resourceUpdateLength := r.resourceUpdate.binaryLength() 109 // signature is the last item in the chunk data 110 copy(r.binaryData[resourceUpdateLength:], r.signature[:]) 111 112 chunk := storage.NewChunk(r.updateAddr, r.binaryData) 113 return chunk, nil 114 } 115 116 // fromChunk populates this structure from chunk data. It does not verify the signature is valid. 117 func (r *SignedResourceUpdate) fromChunk(updateAddr storage.Address, chunkdata []byte) error { 118 // for update chunk layout see SignedResourceUpdate definition 119 120 //deserialize the resource update portion 121 if err := r.resourceUpdate.binaryGet(chunkdata); err != nil { 122 return err 123 } 124 125 // Extract the signature 126 var signature *Signature 127 cursor := r.resourceUpdate.binaryLength() 128 sigdata := chunkdata[cursor : cursor+signatureLength] 129 if len(sigdata) > 0 { 130 signature = &Signature{} 131 copy(signature[:], sigdata) 132 } 133 134 r.signature = signature 135 r.updateAddr = updateAddr 136 r.binaryData = chunkdata 137 138 return nil 139 140 } 141 142 // GetDigest creates the resource update digest used in signatures (formerly known as keyDataHash) 143 // the serialized payload is cached in .binaryData 144 func (r *SignedResourceUpdate) GetDigest() (result common.Hash, err error) { 145 hasher := hashPool.Get().(hash.Hash) 146 defer hashPool.Put(hasher) 147 hasher.Reset() 148 dataLength := r.resourceUpdate.binaryLength() 149 if r.binaryData == nil { 150 r.binaryData = make([]byte, dataLength+signatureLength) 151 if err := r.resourceUpdate.binaryPut(r.binaryData[:dataLength]); err != nil { 152 return result, err 153 } 154 } 155 hasher.Write(r.binaryData[:dataLength]) //everything except the signature. 156 157 return common.BytesToHash(hasher.Sum(nil)), nil 158 } 159 160 // getOwner extracts the address of the resource update signer 161 func getOwner(digest common.Hash, signature Signature) (common.Address, error) { 162 pub, err := crypto.SigToPub(digest.Bytes(), signature[:]) 163 if err != nil { 164 return common.Address{}, err 165 } 166 return crypto.PubkeyToAddress(*pub), nil 167 } 168 169 // verifyResourceOwnerhsip checks that the signer of the update actually owns the resource 170 // H(ownerAddr, metaHash) is computed. If it matches the rootAddr the update chunk is claiming 171 // to update, it is proven that signer of the resource update owns the resource. 172 // See metadataHash in metadata.go for a more detailed explanation 173 func verifyOwner(ownerAddr common.Address, metaHash []byte, rootAddr storage.Address) bool { 174 hasher := hashPool.Get().(hash.Hash) 175 defer hashPool.Put(hasher) 176 hasher.Reset() 177 hasher.Write(metaHash) 178 hasher.Write(ownerAddr.Bytes()) 179 rootAddr2 := hasher.Sum(nil) 180 return bytes.Equal(rootAddr2, rootAddr) 181 }