From 1c832cbce7a521a9d110a613cb4aa3a1c28616a7 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 7 Sep 2020 18:02:44 +0200 Subject: [PATCH] chanfunding: verify inputs are signed in raw tx --- lnwallet/chanfunding/psbt_assembler.go | 23 ++++++++++++ lnwallet/chanfunding/psbt_assembler_test.go | 39 +++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/lnwallet/chanfunding/psbt_assembler.go b/lnwallet/chanfunding/psbt_assembler.go index 69c1c6946..8b53d0fa3 100644 --- a/lnwallet/chanfunding/psbt_assembler.go +++ b/lnwallet/chanfunding/psbt_assembler.go @@ -316,6 +316,14 @@ func (i *PsbtIntent) FinalizeRawTX(rawTx *wire.MsgTx) error { return fmt.Errorf("inputs differ from verified PSBT: %v", err) } + // We also check that we have a signed TX. This is only necessary if the + // FinalizeRawTX is called directly with a wire format TX instead of + // extracting the TX from a PSBT. + err = verifyInputsSigned(rawTx.TxIn) + if err != nil { + return fmt.Errorf("inputs not signed: %v", err) + } + // As far as we can tell, this TX is ok to be used as a funding // transaction. i.State = PsbtFinalized @@ -539,3 +547,18 @@ func verifyInputPrevOutpointsEqual(ins1, ins2 []*wire.TxIn) error { } return nil } + +// verifyInputsSigned verifies that the given list of inputs is non-empty and +// that all the inputs either contain a script signature or a witness stack. +func verifyInputsSigned(ins []*wire.TxIn) error { + if len(ins) == 0 { + return fmt.Errorf("no inputs in transaction") + } + for idx, in := range ins { + if len(in.SignatureScript) == 0 && len(in.Witness) == 0 { + return fmt.Errorf("input %d has no signature data "+ + "attached", idx) + } + } + return nil +} diff --git a/lnwallet/chanfunding/psbt_assembler_test.go b/lnwallet/chanfunding/psbt_assembler_test.go index a58ea38bf..cc40887ad 100644 --- a/lnwallet/chanfunding/psbt_assembler_test.go +++ b/lnwallet/chanfunding/psbt_assembler_test.go @@ -18,6 +18,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" + "github.com/stretchr/testify/require" ) var ( @@ -496,6 +497,44 @@ func TestPsbtFinalize(t *testing.T) { return i.Finalize(p) }, }, + { + name: "raw tx - nil transaction", + expectedErr: "raw transaction is nil", + doFinalize: func(amt int64, p *psbt.Packet, + i *PsbtIntent) error { + + return i.FinalizeRawTX(nil) + }, + }, + { + name: "raw tx - no witness data in raw tx", + expectedErr: "inputs not signed: input 0 has no " + + "signature data attached", + doFinalize: func(amt int64, p *psbt.Packet, + i *PsbtIntent) error { + + rawTx, err := psbt.Extract(p) + require.NoError(t, err) + rawTx.TxIn[0].Witness = nil + + return i.FinalizeRawTX(rawTx) + }, + }, + { + name: "happy path", + expectedErr: "", + doFinalize: func(amt int64, p *psbt.Packet, + i *PsbtIntent) error { + + err := i.Finalize(p) + require.NoError(t, err) + + require.Equal(t, PsbtFinalized, i.State) + require.NotNil(t, i.FinalTX) + + return nil + }, + }, } // Create a simple assembler and ask it to provision a channel to get