mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
loop+loopout: validate hash of swap invoice
This commit fixes a possible exploit by the loop server, where - in a loop out - the server could claim money off-chain, without publishing an on-chain swap htlc. The server could do this by responding with a regular invoice, whose hash is different than the hash in the NewLoopOutSwap request. To prevent the exploit, we validate that the hash of the swap invoice is equal to the hash the client generated.
This commit is contained in:
parent
6da8494a0f
commit
8d7a272fdd
2 changed files with 22 additions and 13 deletions
17
loopout.go
17
loopout.go
|
|
@ -86,12 +86,12 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig,
|
|||
return nil, fmt.Errorf("cannot initiate swap: %v", err)
|
||||
}
|
||||
|
||||
err = validateLoopOutContract(cfg.lnd, currentHeight, request, swapResp)
|
||||
err = validateLoopOutContract(cfg.lnd, currentHeight, request, swapHash, swapResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Instantie a struct that contains all required data to start the swap.
|
||||
// Instantiate a struct that contains all required data to start the swap.
|
||||
initiationTime := time.Now()
|
||||
|
||||
contract := loopdb.LoopOutContract{
|
||||
|
|
@ -660,21 +660,26 @@ func (s *loopOutSwap) sweep(ctx context.Context,
|
|||
// validateLoopOutContract validates the contract parameters against our
|
||||
// request.
|
||||
func validateLoopOutContract(lnd *lndclient.LndServices,
|
||||
height int32,
|
||||
request *OutRequest,
|
||||
height int32, request *OutRequest, swapHash lntypes.Hash,
|
||||
response *newLoopOutResponse) error {
|
||||
|
||||
// Check invoice amounts.
|
||||
chainParams := lnd.ChainParams
|
||||
|
||||
swapInvoiceAmt, err := swap.GetInvoiceAmt(
|
||||
swapInvoiceHash, swapInvoiceAmt, err := swap.DecodeInvoice(
|
||||
chainParams, response.swapInvoice,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prepayInvoiceAmt, err := swap.GetInvoiceAmt(
|
||||
if swapInvoiceHash != swapHash {
|
||||
return fmt.Errorf(
|
||||
"cannot initiate swap, swap invoice hash %v not equal generated swap hash %v",
|
||||
swapInvoiceHash, swapHash)
|
||||
}
|
||||
|
||||
_, prepayInvoiceAmt, err := swap.DecodeInvoice(
|
||||
chainParams, response.prepayInvoice,
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
|||
18
swap/fees.go
18
swap/fees.go
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/zpay32"
|
||||
)
|
||||
|
||||
|
|
@ -26,21 +27,24 @@ func FeeRateAsPercentage(feeRate int64) float64 {
|
|||
return float64(feeRate) / (FeeRateTotalParts / 100)
|
||||
}
|
||||
|
||||
// GetInvoiceAmt gets the invoice amount. It requires an amount to be
|
||||
// specified.
|
||||
func GetInvoiceAmt(params *chaincfg.Params,
|
||||
payReq string) (btcutil.Amount, error) {
|
||||
// DecodeInvoice gets the hash and the amount of an invoice.
|
||||
// It requires an amount to be specified.
|
||||
func DecodeInvoice(params *chaincfg.Params,
|
||||
payReq string) (lntypes.Hash, btcutil.Amount, error) {
|
||||
|
||||
swapPayReq, err := zpay32.Decode(
|
||||
payReq, params,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return lntypes.Hash{}, 0, err
|
||||
}
|
||||
|
||||
if swapPayReq.MilliSat == nil {
|
||||
return 0, errors.New("no amount in invoice")
|
||||
return lntypes.Hash{}, 0, errors.New("no amount in invoice")
|
||||
}
|
||||
|
||||
return swapPayReq.MilliSat.ToSatoshis(), nil
|
||||
var hash lntypes.Hash
|
||||
copy(hash[:], swapPayReq.PaymentHash[:])
|
||||
|
||||
return hash, swapPayReq.MilliSat.ToSatoshis(), nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue