git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/object/fmt.go (about) 1 package object 2 3 import ( 4 "bytes" 5 "crypto/ecdsa" 6 "crypto/sha256" 7 "errors" 8 "fmt" 9 10 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" 11 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum" 12 frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" 13 oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" 14 ) 15 16 var ( 17 errCheckSumMismatch = errors.New("payload checksum mismatch") 18 errCheckSumNotSet = errors.New("payload checksum is not set") 19 errIncorrectID = errors.New("incorrect object identifier") 20 ) 21 22 // CalculatePayloadChecksum calculates and returns checksum of 23 // object payload bytes. 24 func CalculatePayloadChecksum(payload []byte) checksum.Checksum { 25 var res checksum.Checksum 26 checksum.Calculate(&res, checksum.SHA256, payload) 27 28 return res 29 } 30 31 // CalculateAndSetPayloadChecksum calculates checksum of current 32 // object payload and writes it to the object. 33 func CalculateAndSetPayloadChecksum(obj *Object) { 34 obj.SetPayloadChecksum( 35 CalculatePayloadChecksum(obj.Payload()), 36 ) 37 } 38 39 // VerifyPayloadChecksum checks if payload checksum in the object 40 // corresponds to its payload. 41 func VerifyPayloadChecksum(obj *Object) error { 42 actual := CalculatePayloadChecksum(obj.Payload()) 43 44 cs, set := obj.PayloadChecksum() 45 if !set { 46 return errCheckSumNotSet 47 } 48 49 if !bytes.Equal(cs.Value(), actual.Value()) { 50 return errCheckSumMismatch 51 } 52 53 return nil 54 } 55 56 // CalculateID calculates identifier for the object. 57 func CalculateID(obj *Object) (oid.ID, error) { 58 var id oid.ID 59 id.SetSHA256(sha256.Sum256(obj.ToV2().GetHeader().StableMarshal(nil))) 60 61 return id, nil 62 } 63 64 // CalculateAndSetID calculates identifier for the object 65 // and writes the result to it. 66 func CalculateAndSetID(obj *Object) error { 67 id, err := CalculateID(obj) 68 if err != nil { 69 return err 70 } 71 72 obj.SetID(id) 73 74 return nil 75 } 76 77 // VerifyID checks if identifier in the object corresponds to 78 // its structure. 79 func VerifyID(obj *Object) error { 80 id, err := CalculateID(obj) 81 if err != nil { 82 return err 83 } 84 85 oID, set := obj.ID() 86 if !set { 87 return errOIDNotSet 88 } 89 90 if !id.Equals(oID) { 91 return errIncorrectID 92 } 93 94 return nil 95 } 96 97 // CalculateAndSetSignature signs id with provided key and sets that signature to 98 // the object. 99 func CalculateAndSetSignature(key ecdsa.PrivateKey, obj *Object) error { 100 oID, set := obj.ID() 101 if !set { 102 return errOIDNotSet 103 } 104 105 sig, err := oID.CalculateIDSignature(key) 106 if err != nil { 107 return err 108 } 109 110 obj.SetSignature(&sig) 111 112 return nil 113 } 114 115 // VerifyIDSignature verifies object ID signature. 116 func (o *Object) VerifyIDSignature() bool { 117 m := (*object.Object)(o) 118 119 sigV2 := m.GetSignature() 120 if sigV2 == nil { 121 return false 122 } 123 124 idV2 := m.GetObjectID() 125 if idV2 == nil { 126 return false 127 } 128 129 var sig frostfscrypto.Signature 130 131 return sig.ReadFromV2(*sigV2) == nil && sig.Verify(idV2.StableMarshal(nil)) 132 } 133 134 // SetIDWithSignature sets object identifier and signature. 135 func SetIDWithSignature(key ecdsa.PrivateKey, obj *Object) error { 136 if err := CalculateAndSetID(obj); err != nil { 137 return fmt.Errorf("could not set identifier: %w", err) 138 } 139 140 if err := CalculateAndSetSignature(key, obj); err != nil { 141 return fmt.Errorf("could not set signature: %w", err) 142 } 143 144 return nil 145 } 146 147 // SetVerificationFields calculates and sets all verification fields of the object. 148 func SetVerificationFields(key ecdsa.PrivateKey, obj *Object) error { 149 CalculateAndSetPayloadChecksum(obj) 150 151 return SetIDWithSignature(key, obj) 152 } 153 154 // CheckVerificationFields checks all verification fields of the object. 155 func CheckVerificationFields(obj *Object) error { 156 if err := CheckHeaderVerificationFields(obj); err != nil { 157 return fmt.Errorf("invalid header structure: %w", err) 158 } 159 160 if err := VerifyPayloadChecksum(obj); err != nil { 161 return fmt.Errorf("invalid payload checksum: %w", err) 162 } 163 164 return nil 165 } 166 167 var errInvalidSignature = errors.New("invalid signature") 168 169 // CheckHeaderVerificationFields checks all verification fields except payload. 170 func CheckHeaderVerificationFields(obj *Object) error { 171 if !obj.VerifyIDSignature() { 172 return errInvalidSignature 173 } 174 175 if err := VerifyID(obj); err != nil { 176 return fmt.Errorf("invalid identifier: %w", err) 177 } 178 179 return nil 180 }