storj.io/uplink@v1.13.0/private/piecestore/verification.go (about)

     1  // Copyright (C) 2019 Storj Labs, Inc.
     2  // See LICENSE for copying information.
     3  
     4  package piecestore
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"time"
    10  
    11  	"github.com/zeebo/errs"
    12  
    13  	"storj.io/common/identity"
    14  	"storj.io/common/pb"
    15  	"storj.io/common/signing"
    16  )
    17  
    18  const pieceHashExpiration = 24 * time.Hour
    19  
    20  var (
    21  	// ErrInternal is an error class for internal errors.
    22  	ErrInternal = errs.Class("internal")
    23  	// ErrProtocol is an error class for unexpected protocol sequence.
    24  	ErrProtocol = errs.Class("protocol")
    25  	// ErrVerifyUntrusted is an error in case there is a trust issue.
    26  	ErrVerifyUntrusted = errs.Class("untrusted")
    27  	// ErrStorageNodeInvalidResponse is an error when a storage node returns a response with invalid data.
    28  	ErrStorageNodeInvalidResponse = errs.Class("storage node has returned an invalid response")
    29  )
    30  
    31  // VerifyPieceHash verifies piece hash which is sent by peer.
    32  func (client *Client) VerifyPieceHash(ctx context.Context, peer *identity.PeerIdentity, limit *pb.OrderLimit, hash *pb.PieceHash, expectedHash []byte, algorithm pb.PieceHashAlgorithm) (err error) {
    33  	defer mon.Task()(&ctx)(&err)
    34  	if peer == nil || limit == nil || hash == nil || len(expectedHash) == 0 {
    35  		return ErrProtocol.New("invalid arguments")
    36  	}
    37  	if limit.PieceId != hash.PieceId {
    38  		return ErrProtocol.New("piece id changed") // TODO: report rpc status bad message
    39  	}
    40  	if algorithm != hash.HashAlgorithm {
    41  		return ErrVerifyUntrusted.New("hash algorithms don't match expected: %s got: %s", algorithm, hash.HashAlgorithm)
    42  	}
    43  	if !bytes.Equal(hash.Hash, expectedHash) {
    44  		return ErrVerifyUntrusted.New("hashes don't match") // TODO: report rpc status bad message
    45  	}
    46  
    47  	if err := signing.VerifyPieceHashSignature(ctx, signing.SigneeFromPeerIdentity(peer), hash); err != nil {
    48  		return ErrVerifyUntrusted.New("invalid hash signature: %v", err) // TODO: report rpc status bad message
    49  	}
    50  
    51  	if hash.Timestamp.Before(time.Now().Add(-pieceHashExpiration)) {
    52  		return ErrStorageNodeInvalidResponse.New("piece has timestamp is too old (%v). Required to be not older than %s",
    53  			hash.Timestamp, pieceHashExpiration,
    54  		)
    55  	}
    56  
    57  	return nil
    58  }