package ante import ( "bytes" "encoding/base64" "encoding/hex" "fmt" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/crypto/types/multisig" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/cosmos/cosmos-sdk/x/auth/types" ) var ( // simulation signature values used to estimate gas consumption key = make([]byte, secp256k1.PubKeySize) simSecp256k1Pubkey = &secp256k1.PubKey{Key: key} simSecp256k1Sig [64]byte _ authsigning.SigVerifiableTx = (*legacytx.StdTx)(nil) // assert StdTx implements SigVerifiableTx ) func init() { // This decodes a valid hex string into a sepc256k1Pubkey for use in transaction simulation bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A") copy(key, bz) simSecp256k1Pubkey.Key = key } // SignatureVerificationGasConsumer is the type of function that is used to both // consume gas when verifying signatures and also to accept or reject different types of pubkeys // This is where apps can define their own PubKey type SignatureVerificationGasConsumer = func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error // SetPubKeyDecorator sets PubKeys in context for any signer which does not already have pubkey set // PubKeys must be set in context for all signers before any other sigverify decorators run // CONTRACT: Tx must implement SigVerifiableTx interface type SetPubKeyDecorator struct { ak AccountKeeper } func NewSetPubKeyDecorator(ak AccountKeeper) SetPubKeyDecorator { return SetPubKeyDecorator{ ak: ak, } } func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { sigTx, ok := tx.(authsigning.SigVerifiableTx) if !ok { return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type") } pubkeys, err := sigTx.GetPubKeys() if err != nil { return ctx, err } signers := sigTx.GetSigners() for i, pk := range pubkeys { // PublicKey was omitted from slice since it has already been set in context if pk == nil { if !simulate { continue } pk = simSecp256k1Pubkey } // Only make check if simulate=false if !simulate && !bytes.Equal(pk.Address(), signers[i]) { return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "pubKey does not match signer address %s with signer index: %d", signers[i], i) } acc, err := GetSignerAcc(ctx, spkd.ak, signers[i]) if err != nil { return ctx, err } // account already has pubkey set,no need to reset if acc.GetPubKey() != nil { continue } err = acc.SetPubKey(pk) if err != nil { return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, err.Error()) } spkd.ak.SetAccount(ctx, acc) } // Also emit the following events, so that txs can be indexed by these // indices: // - signature (via `tx.signature=''`), // - concat(address,"/",sequence) (via `tx.acc_seq='cosmos1abc...def/42'`). sigs, err := sigTx.GetSignaturesV2() if err != nil { return ctx, err } var events sdk.Events for i, sig := range sigs { events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyAccountSequence, fmt.Sprintf("%s/%d", signers[i], sig.Sequence)), )) sigBzs, err := signatureDataToBz(sig.Data) if err != nil { return ctx, err } for _, sigBz := range sigBzs { events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeySignature, base64.StdEncoding.EncodeToString(sigBz)), )) } } ctx.EventManager().EmitEvents(events) return next(ctx, tx, simulate) } // Consume parameter-defined amount of gas for each signature according to the passed-in SignatureVerificationGasConsumer function // before calling the next AnteHandler // CONTRACT: Pubkeys are set in context for all signers before this decorator runs // CONTRACT: Tx must implement SigVerifiableTx interface type SigGasConsumeDecorator struct { ak AccountKeeper sigGasConsumer SignatureVerificationGasConsumer } func NewSigGasConsumeDecorator(ak AccountKeeper, sigGasConsumer SignatureVerificationGasConsumer) SigGasConsumeDecorator { if sigGasConsumer == nil { sigGasConsumer = DefaultSigVerificationGasConsumer } return SigGasConsumeDecorator{ ak: ak, sigGasConsumer: sigGasConsumer, } } func (sgcd SigGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { sigTx, ok := tx.(authsigning.SigVerifiableTx) if !ok { return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type") } params := sgcd.ak.GetParams(ctx) sigs, err := sigTx.GetSignaturesV2() if err != nil { return ctx, err } // stdSigs contains the sequence number, account number, and signatures. // When simulating, this would just be a 0-length slice. signerAddrs := sigTx.GetSigners() for i, sig := range sigs { signerAcc, err := GetSignerAcc(ctx, sgcd.ak, signerAddrs[i]) if err != nil { return ctx, err } pubKey := signerAcc.GetPubKey() // In simulate mode the transaction comes with no signatures, thus if the // account's pubkey is nil, both signature verification and gasKVStore.Set() // shall consume the largest amount, i.e. it takes more gas to verify // secp256k1 keys than ed25519 ones. if simulate && pubKey == nil { pubKey = simSecp256k1Pubkey } // make a SignatureV2 with PubKey filled in from above sig = signing.SignatureV2{ PubKey: pubKey, Data: sig.Data, Sequence: sig.Sequence, } err = sgcd.sigGasConsumer(ctx.GasMeter(), sig, params) if err != nil { return ctx, err } } return next(ctx, tx, simulate) } // Verify all signatures for a tx and return an error if any are invalid. Note, // the SigVerificationDecorator will not check signatures on ReCheck. // // CONTRACT: Pubkeys are set in context for all signers before this decorator runs // CONTRACT: Tx must implement SigVerifiableTx interface type SigVerificationDecorator struct { ak AccountKeeper signModeHandler authsigning.SignModeHandler } func NewSigVerificationDecorator(ak AccountKeeper, signModeHandler authsigning.SignModeHandler) SigVerificationDecorator { return SigVerificationDecorator{ ak: ak, signModeHandler: signModeHandler, } } // OnlyLegacyAminoSigners checks SignatureData to see if all // signers are using SIGN_MODE_LEGACY_AMINO_JSON. If this is the case // then the corresponding SignatureV2 struct will not have account sequence // explicitly set, and we should skip the explicit verification of sig.Sequence // in the SigVerificationDecorator's AnteHandler function. func OnlyLegacyAminoSigners(sigData signing.SignatureData) bool { switch v := sigData.(type) { case *signing.SingleSignatureData: return v.SignMode == signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON case *signing.MultiSignatureData: for _, s := range v.Signatures { if !OnlyLegacyAminoSigners(s) { return false } } return true default: return false } } func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { sigTx, ok := tx.(authsigning.SigVerifiableTx) if !ok { return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type") } // stdSigs contains the sequence number, account number, and signatures. // When simulating, this would just be a 0-length slice. sigs, err := sigTx.GetSignaturesV2() if err != nil { return ctx, err } signerAddrs := sigTx.GetSigners() // check that signer length and signature length are the same if len(sigs) != len(signerAddrs) { return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs)) } for i, sig := range sigs { acc, err := GetSignerAcc(ctx, svd.ak, signerAddrs[i]) if err != nil { return ctx, err } // retrieve pubkey pubKey := acc.GetPubKey() if !simulate && pubKey == nil { return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set") } // Check account sequence number. if sig.Sequence != acc.GetSequence() { return ctx, sdkerrors.Wrapf( sdkerrors.ErrWrongSequence, "account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence, ) } // retrieve signer data genesis := ctx.BlockHeight() == 0 chainID := ctx.ChainID() var accNum uint64 if !genesis { accNum = acc.GetAccountNumber() } signerData := authsigning.SignerData{ Address: acc.GetAddress().String(), ChainID: chainID, AccountNumber: accNum, Sequence: acc.GetSequence(), PubKey: pubKey, } // no need to verify signatures on recheck tx if !simulate && !ctx.IsReCheckTx() { err := authsigning.VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, tx) if err != nil { var errMsg string if OnlyLegacyAminoSigners(sig.Data) { // If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number, // and therefore communicate sequence number as a potential cause of error. errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", accNum, acc.GetSequence(), chainID) } else { errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s)", accNum, chainID) } return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg) } } } return next(ctx, tx, simulate) } // IncrementSequenceDecorator handles incrementing sequences of all signers. // Use the IncrementSequenceDecorator decorator to prevent replay attacks. Note, // there is no need to execute IncrementSequenceDecorator on RecheckTX since // CheckTx would already bump the sequence number. // // NOTE: Since CheckTx and DeliverTx state are managed separately, subsequent and // sequential txs orginating from the same account cannot be handled correctly in // a reliable way unless sequence numbers are managed and tracked manually by a // client. It is recommended to instead use multiple messages in a tx. type IncrementSequenceDecorator struct { ak AccountKeeper } func NewIncrementSequenceDecorator(ak AccountKeeper) IncrementSequenceDecorator { return IncrementSequenceDecorator{ ak: ak, } } func (isd IncrementSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { sigTx, ok := tx.(authsigning.SigVerifiableTx) if !ok { return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type") } // increment sequence of all signers for _, addr := range sigTx.GetSigners() { acc := isd.ak.GetAccount(ctx, addr) if err := acc.SetSequence(acc.GetSequence() + 1); err != nil { panic(err) } isd.ak.SetAccount(ctx, acc) } return next(ctx, tx, simulate) } // ValidateSigCountDecorator takes in Params and returns errors if there are too many signatures in the tx for the given params // otherwise it calls next AnteHandler // Use this decorator to set parameterized limit on number of signatures in tx // CONTRACT: Tx must implement SigVerifiableTx interface type ValidateSigCountDecorator struct { ak AccountKeeper } func NewValidateSigCountDecorator(ak AccountKeeper) ValidateSigCountDecorator { return ValidateSigCountDecorator{ ak: ak, } } func (vscd ValidateSigCountDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { sigTx, ok := tx.(authsigning.SigVerifiableTx) if !ok { return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a sigTx") } params := vscd.ak.GetParams(ctx) pubKeys, err := sigTx.GetPubKeys() if err != nil { return ctx, err } sigCount := 0 for _, pk := range pubKeys { sigCount += CountSubKeys(pk) if uint64(sigCount) > params.TxSigLimit { return ctx, sdkerrors.Wrapf(sdkerrors.ErrTooManySignatures, "signatures: %d, limit: %d", sigCount, params.TxSigLimit) } } return next(ctx, tx, simulate) } // DefaultSigVerificationGasConsumer is the default implementation of SignatureVerificationGasConsumer. It consumes gas // for signature verification based upon the public key type. The cost is fetched from the given params and is matched // by the concrete type. func DefaultSigVerificationGasConsumer( meter sdk.GasMeter, sig signing.SignatureV2, params types.Params, ) error { pubkey := sig.PubKey switch pubkey := pubkey.(type) { case *ed25519.PubKey: meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") return sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "ED25519 public keys are unsupported") case *secp256k1.PubKey: meter.ConsumeGas(params.SigVerifyCostSecp256k1, "ante verify: secp256k1") return nil case *secp256r1.PubKey: meter.ConsumeGas(params.SigVerifyCostSecp256r1(), "ante verify: secp256r1") return nil case multisig.PubKey: multisignature, ok := sig.Data.(*signing.MultiSignatureData) if !ok { return fmt.Errorf("expected %T, got, %T", &signing.MultiSignatureData{}, sig.Data) } err := ConsumeMultisignatureVerificationGas(meter, multisignature, pubkey, params, sig.Sequence) if err != nil { return err } return nil default: return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey) } } // ConsumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature func ConsumeMultisignatureVerificationGas( meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey, params types.Params, accSeq uint64, ) error { size := sig.BitArray.Count() sigIndex := 0 for i := 0; i < size; i++ { if !sig.BitArray.GetIndex(i) { continue } sigV2 := signing.SignatureV2{ PubKey: pubkey.GetPubKeys()[i], Data: sig.Signatures[sigIndex], Sequence: accSeq, } err := DefaultSigVerificationGasConsumer(meter, sigV2, params) if err != nil { return err } sigIndex++ } return nil } // GetSignerAcc returns an account for a given address that is expected to sign // a transaction. func GetSignerAcc(ctx sdk.Context, ak AccountKeeper, addr sdk.AccAddress) (types.AccountI, error) { if acc := ak.GetAccount(ctx, addr); acc != nil { return acc, nil } return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) } // CountSubKeys counts the total number of keys for a multi-sig public key. func CountSubKeys(pub cryptotypes.PubKey) int { v, ok := pub.(*kmultisig.LegacyAminoPubKey) if !ok { return 1 } numKeys := 0 for _, subkey := range v.GetPubKeys() { numKeys += CountSubKeys(subkey) } return numKeys } // signatureDataToBz converts a SignatureData into raw bytes signature. // For SingleSignatureData, it returns the signature raw bytes. // For MultiSignatureData, it returns an array of all individual signatures, // as well as the aggregated signature. func signatureDataToBz(data signing.SignatureData) ([][]byte, error) { if data == nil { return nil, fmt.Errorf("got empty SignatureData") } switch data := data.(type) { case *signing.SingleSignatureData: return [][]byte{data.Signature}, nil case *signing.MultiSignatureData: sigs := [][]byte{} var err error for _, d := range data.Signatures { nestedSigs, err := signatureDataToBz(d) if err != nil { return nil, err } sigs = append(sigs, nestedSigs...) } multisig := cryptotypes.MultiSignature{ Signatures: sigs, } aggregatedSig, err := multisig.Marshal() if err != nil { return nil, err } sigs = append(sigs, aggregatedSig) return sigs, nil default: return nil, sdkerrors.ErrInvalidType.Wrapf("unexpected signature data type %T", data) } }