Merge pull request #3505 from Crypt-iQ/invoice-param-checks-0913
zpay32: check route+hop hints while decoding
This commit is contained in:
commit
811c2df75a
@ -3,6 +3,7 @@ package zpay32
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -71,12 +72,20 @@ const (
|
|||||||
// fieldType9 contains one or more bytes for signaling features
|
// fieldType9 contains one or more bytes for signaling features
|
||||||
// supported or required by the receiver.
|
// supported or required by the receiver.
|
||||||
fieldType9 = 5
|
fieldType9 = 5
|
||||||
|
|
||||||
|
// maxInvoiceLength is the maximum total length an invoice can have.
|
||||||
|
// This is chosen to be the maximum number of bytes that can fit into a
|
||||||
|
// single QR code: https://en.wikipedia.org/wiki/QR_code#Storage
|
||||||
|
maxInvoiceLength = 7089
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// InvoiceFeatures holds the set of all known feature bits that are
|
// InvoiceFeatures holds the set of all known feature bits that are
|
||||||
// exposed as BOLT 11 features.
|
// exposed as BOLT 11 features.
|
||||||
InvoiceFeatures = map[lnwire.FeatureBit]string{}
|
InvoiceFeatures = map[lnwire.FeatureBit]string{}
|
||||||
|
|
||||||
|
// ErrInvoiceTooLarge is returned when an invoice exceeds maxInvoiceLength.
|
||||||
|
ErrInvoiceTooLarge = errors.New("invoice is too large")
|
||||||
)
|
)
|
||||||
|
|
||||||
// MessageSigner is passed to the Encode method to provide a signature
|
// MessageSigner is passed to the Encode method to provide a signature
|
||||||
@ -263,6 +272,12 @@ func NewInvoice(net *chaincfg.Params, paymentHash [32]byte,
|
|||||||
func Decode(invoice string, net *chaincfg.Params) (*Invoice, error) {
|
func Decode(invoice string, net *chaincfg.Params) (*Invoice, error) {
|
||||||
decodedInvoice := Invoice{}
|
decodedInvoice := Invoice{}
|
||||||
|
|
||||||
|
// Before bech32 decoding the invoice, make sure that it is not too large.
|
||||||
|
// This is done as an anti-DoS measure since bech32 decoding is expensive.
|
||||||
|
if len(invoice) > maxInvoiceLength {
|
||||||
|
return nil, ErrInvoiceTooLarge
|
||||||
|
}
|
||||||
|
|
||||||
// Decode the invoice using the modified bech32 decoder.
|
// Decode the invoice using the modified bech32 decoder.
|
||||||
hrp, data, err := decodeBech32(invoice)
|
hrp, data, err := decodeBech32(invoice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -467,6 +482,12 @@ func (invoice *Invoice) Encode(signer MessageSigner) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Before returning, check that the bech32 encoded string is not greater
|
||||||
|
// than our largest supported invoice size.
|
||||||
|
if len(b32) > maxInvoiceLength {
|
||||||
|
return "", ErrInvoiceTooLarge
|
||||||
|
}
|
||||||
|
|
||||||
return b32, nil
|
return b32, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,21 +539,6 @@ func validateInvoice(invoice *Invoice) error {
|
|||||||
return fmt.Errorf("neither description nor description hash set")
|
return fmt.Errorf("neither description nor description hash set")
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll restrict invoices to include up to 20 different private route
|
|
||||||
// hints. We do this to avoid overly large invoices.
|
|
||||||
if len(invoice.RouteHints) > 20 {
|
|
||||||
return fmt.Errorf("too many private routes: %d",
|
|
||||||
len(invoice.RouteHints))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each route hint can have at most 20 hops.
|
|
||||||
for i, routeHint := range invoice.RouteHints {
|
|
||||||
if len(routeHint) > 20 {
|
|
||||||
return fmt.Errorf("route hint %d has too many extra "+
|
|
||||||
"hops: %d", i, len(routeHint))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that we support the field lengths.
|
// Check that we support the field lengths.
|
||||||
if len(invoice.PaymentHash) != 32 {
|
if len(invoice.PaymentHash) != 32 {
|
||||||
return fmt.Errorf("unsupported payment hash length: %d",
|
return fmt.Errorf("unsupported payment hash length: %d",
|
||||||
@ -870,6 +876,7 @@ func parseRouteHint(data []byte) ([]HopHint, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that base256Data is a multiple of hopHintLen.
|
||||||
if len(base256Data)%hopHintLen != 0 {
|
if len(base256Data)%hopHintLen != 0 {
|
||||||
return nil, fmt.Errorf("expected length multiple of %d bytes, "+
|
return nil, fmt.Errorf("expected length multiple of %d bytes, "+
|
||||||
"got %d", hopHintLen, len(base256Data))
|
"got %d", hopHintLen, len(base256Data))
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user