frostfs-node/pkg/innerring/processors/container/process_container.go
Leonard Lyubich 369c12b702 [#505] morph/container: Verify signature of deleting container ID
Get all owner keys and verify container ID signature until first success. If
none of the keys match, then prohibit deletion. Thus, the delete operation
is only allowed to the owner of the container. With this approach, a
separate check for key ownership is not required.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
2021-05-25 16:35:52 +03:00

134 lines
3.3 KiB
Go

package container
import (
"crypto/elliptic"
"crypto/sha256"
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
containerSDK "github.com/nspcc-dev/neofs-api-go/pkg/container"
"github.com/nspcc-dev/neofs-node/pkg/core/container"
containerEvent "github.com/nspcc-dev/neofs-node/pkg/morph/event/container"
"go.uber.org/zap"
)
// Process new container from the user by checking container sanity
// and sending approve tx back to morph.
func (cp *Processor) processContainerPut(put *containerEvent.Put) {
if !cp.alphabetState.IsAlphabet() {
cp.log.Info("non alphabet mode, ignore container put")
return
}
err := cp.checkPutContainer(put)
if err != nil {
cp.log.Error("put container check failed",
zap.String("error", err.Error()),
)
return
}
cp.approvePutContainer(put)
}
func (cp *Processor) checkPutContainer(e *containerEvent.Put) error {
// verify signature
key, err := keys.NewPublicKeyFromBytes(e.PublicKey(), elliptic.P256())
if err != nil {
return fmt.Errorf("invalid key: %w", err)
}
binCnr := e.Container()
tableHash := sha256.Sum256(binCnr)
if !key.Verify(e.Signature(), tableHash[:]) {
return errors.New("invalid signature")
}
// unmarshal container structure
cnr := containerSDK.New()
err = cnr.Unmarshal(binCnr)
if err != nil {
return fmt.Errorf("invalid binary container: %w", err)
}
// perform format check
err = container.CheckFormat(cnr)
if err != nil {
return fmt.Errorf("incorrect container format: %w", err)
}
return cp.checkKeyOwnership(cnr, key)
}
func (cp *Processor) approvePutContainer(e *containerEvent.Put) {
// FIXME: here we should try notary invoke
// FIXME: here we should bind key to owner if needed
err := cp.cnrClient.Put(e.Container(), e.PublicKey(), e.Signature())
if err != nil {
cp.log.Error("could not approve put container",
zap.String("error", err.Error()),
)
}
}
// Process delete container operation from the user by checking container sanity
// and sending approve tx back to morph.
func (cp *Processor) processContainerDelete(delete *containerEvent.Delete) {
if !cp.alphabetState.IsAlphabet() {
cp.log.Info("non alphabet mode, ignore container delete")
return
}
err := cp.checkDeleteContainer(delete)
if err != nil {
cp.log.Error("delete container check failed",
zap.String("error", err.Error()),
)
return
}
cp.approveDeleteContainer(delete)
}
func (cp *Processor) checkDeleteContainer(e *containerEvent.Delete) error {
cid := e.ContainerID()
// receive owner of the related container
cnr, err := cp.cnrClient.Get(cid)
if err != nil {
return fmt.Errorf("could not receive the container: %w", err)
}
// receive all owner keys
ownerKeys, err := cp.idClient.AccountKeys(cnr.OwnerID())
if err != nil {
return fmt.Errorf("could not received owner keys %s: %w", cnr.OwnerID(), err)
}
// verify signature
cidHash := sha256.Sum256(cid)
sig := e.Signature()
for _, ownerKey := range ownerKeys {
if ownerKey.Verify(sig, cidHash[:]) {
return nil
}
}
return errors.New("signature verification failed on all owner keys ")
}
func (cp *Processor) approveDeleteContainer(e *containerEvent.Delete) {
// FIXME: here we should try notary invoke
err := cp.cnrClient.Delete(e.ContainerID(), e.Signature())
if err != nil {
cp.log.Error("could not approve delete container",
zap.String("error", err.Error()),
)
}
}