From d08f03552c46010916fd1c010c9308343aab7b2d Mon Sep 17 00:00:00 2001 From: nsa Date: Wed, 8 Apr 2020 17:53:06 -0400 Subject: [PATCH 1/2] psbt: define MaxPsbtKeyLength and check against it when decoding This commit defines MaxPsbtKeyLength and checks that decoding a key from a PSBT blob doesn't attempt to allocate too much memory. --- psbt/psbt.go | 4 ++++ psbt/utils.go | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/psbt/psbt.go b/psbt/psbt.go index 6d829e3..73126c3 100644 --- a/psbt/psbt.go +++ b/psbt/psbt.go @@ -33,6 +33,10 @@ var ( //less than 4M. const MaxPsbtValueLength = 4000000 +// MaxPsbtKeyLength is the length of the largest key that we'll successfully +// deserialize from the wire. Anything more will return ErrInvalidKeydata. +const MaxPsbtKeyLength = 10000 + var ( // ErrInvalidPsbtFormat is a generic error for any situation in which a diff --git a/psbt/utils.go b/psbt/utils.go index 5af0b14..c7f281e 100644 --- a/psbt/utils.go +++ b/psbt/utils.go @@ -237,6 +237,11 @@ func getKey(r io.Reader) (int, []byte, error) { return -1, nil, nil } + // Check that we don't attempt to decode a dangerously large key. + if count > MaxPsbtKeyLength { + return -1, nil, ErrInvalidKeydata + } + // Next, we ready out the designated number of bytes, which may include // a type, key, and optional data. keyTypeAndData := make([]byte, count) From f06d6af2f04c664694e29e3b0cddb31ad83609b7 Mon Sep 17 00:00:00 2001 From: nsa Date: Wed, 8 Apr 2020 17:54:59 -0400 Subject: [PATCH 2/2] psbt: return ErrInvalidKeydata if value isn't a 32-bit uint This commit fixes a panic when deserializing PSBTs in raw binary. If the key type was SighashType and the value was not 4 bytes long, the call to binary.LittleEndian.Uint32(value) would panic as the function expects 4 bytes to parse into a uint32. We now perform a sanity check that asserts that the value is 4 bytes long. --- psbt/partial_input.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/psbt/partial_input.go b/psbt/partial_input.go index 3b4d123..3db042f 100644 --- a/psbt/partial_input.go +++ b/psbt/partial_input.go @@ -141,6 +141,12 @@ func (pi *PInput) deserialize(r io.Reader) error { return ErrInvalidKeydata } + // Bounds check on value here since the sighash type must be a + // 32-bit unsigned integer. + if len(value) != 4 { + return ErrInvalidKeydata + } + shtype := txscript.SigHashType( binary.LittleEndian.Uint32(value), )