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  }